十一月, 2007


30
十一 07

send_arp的一个脚本

send_arp 包含在RedHat的集群组件piranha里。send_arp.c

send_arp是一个比较底层的程序,在LVS集群里,要用到。

它的主要作用,我的理解是,用来让交换机或者路由器更新本机在对方MAC缓存表里的信息,特别是路由器。

比如,当你对调了两台设备的IP地址时,可能会有一段时间(视情况而定)这两台机器死活访问不了网关。这是因为网关(路由器)里的MAC表缓存里存的还是原来的MAC地址。

下面是在网上看到一个脚本,大致可以展示send_arp的语法。不过,这个脚本,想了半天,难道是用来防止本机被ARP欺骗的?还是要跟别人抢IP?

#!/bin/sh
#
mac1=`ifconfig eth0 |grep “HWaddr” |cut -c39-55 `

echo Sendarp start. send 你的IP地址 = $mac1

while true;
do
send_arp 你的IP地址 $mac1 你的IP地址 ff:ff:ff:ff:ff:ff
sleep 2
done


27
十一 07

postfix的几个必须知道的参数

查看postfix的配置参数用:
#postconf

修改参数使用:
postconf -e hash_queue_depth=3 (默认是1)

hash_queue_names = deferred,defer,active,incoming (默认只有deferred,defer)

postfix check
postfix reload

default_process_limit 这个参数用来设置传输服务可同时启动的进程上限。

default_destination_limit

default_destination_concurrency_limit    传输服务(定义于master.cf)对于同一目的地同时投递量的上限。此参数的限制对象是“目的地”而非“传输服务”本身。

default_transport_concurrency_limit     决定各个传输服务同时投递量的上限。


27
十一 07

Linux文件权限位

       The  letters ‘rwxXstugo’ select the new permissions for the affected users: read (r), write (w), execute (or access for directories) (x), execute only if the file is a directory or already has execute permission for some user (X), set user or group ID on  execution  (s),  sticky  (t),  the permissions granted to the user who owns the file (u), the permissions granted to other users who are members of the file’s group (g), and the permissions granted to users that are in neither of the  two  preceding categories (o).

1. 4000—调整用户号
   2000—调整组号
   1000—粘着置位 

2. suid/guid程序
   当一个程序的用户或组被置位的时候,即4000或2000时,可实现某些特殊的功能一般来说,
   一个运行中的程序为运行这个程序的用户所拥有,但如果该程序是suid/guid程序,则运行
   的程序则为文件所有者拥有,运行中的程序在程序运行期间拥有文件所有者的全部权限
   如果一个普通用户运行了一个属于根用户的带s标志的程序,则该程序不考虑用户权限,
   自动拥有在系统中读/写任何文件及目录的特权,对于guid程序也是一样的。
   最典型的要数/usr/bin/passwd程序了,-r-s–x–x ,可帮助普通用户更改在系统中的密码,
   利用的就是suid的作用。 但也要严格设置这种权限,避免破坏性,

因为如果你的suid程序是/bin/bash的话,则会导致严重后果,一个普通用户若在某个短时间
取得过root权限,他就能设置一个suid程序/binb/bash来取得根特权。
(若拿它来破坏别人的系统,后果自负)

# cp /bin/bash /home/jephe/.backdoor

# chmod 4755 /home/jephe/.backdoor

这样当攻击者执行了/home/jephe/.backdoor后就得到了根特权,可用id命令显示suid=0

因此一个管理员应定期运行检查程序检查系统内有无异常的suid/guid程序:象下面这样的命令

#find / -type f \( -perm -04000 -o -perm -02000 \) \-exec ls -lg {} \; >suid-sguid-results

把上面的命令放入cron job并邮递文件suid-guid-resuilts给管理员邮箱帐号.

3. 程序的t属性
粘着位 告诉系统在程序完成后在内存中保存一份运行程序的备份,如该程序常用,可为系统
节省点时间,不用每次从磁盘加载到内存
4.目录的s属性 

目录的S属性使得在该目录下创建的任何文件及目录属于该目录所拥有的组。
例如在apache中为个人设置WEB目录的时候,如果给apache分配的组名为httpd.
则:

#chown -R jephe.httpd ~jephe/public_html
#chmod -R 2770 ~jephe/public_html

确保在public_html中创建新的文件或子目录时,新创建的文件设置了组ID。

另外如有两个用户a和b都属于组c,则希望在某目录下a创建的文件也能被b修改,则
可设置该目录chmod +s属性,同时设置a和b的默认umask为770。

5. 目录的T属性
设置了目录的T属性后1000,由只有该目录的所有者及root才能删除该目录,如
/tmp目录就是drwxrwxrwt

6.  文件及目录的三种时间位 
每个Linux文件有三种保存着的时间日期标志。

文件建立时间 (实际上是文件I节点建立时间) 
文件最后访问时间
文件最后修改时间
默认ls -l时显示的是文件最后修改时间,也可用ls -l –time=atime(文件最后访问时间)
ls -l –time=ctime(文件建立时间)

可用touch命令改变时间日期标志,从而可隐蔽攻击者对文件放置特洛伊木马后对文件时间
的修改

7。可用chattr改变文件及目录的属性。

有时你会发现对某个文件即使是root用户也不能修改或添加新内容,那很可能是该文件被
用chattr命令设置成不可更改或附加新内容了。你必须先用chattr去掉这些属性再更改内容。 


26
十一 07

将InnoDB的表格式转换为MyISAM格式

ALTER TABLE `tablename` ENGINE = MYISAM


26
十一 07

Linux 中软件 RAID 使用常见问题解决

注:转贴自 IBM
张 志斌 (linuxaid@tom.com), 软件工程师, 软件工程师

在文章“Linux 中软件 RAID 的使用”中我们讲述了 Linux 系统中软 RAID 的基本概念和如何使用 mdadm 程序来管理软 RAID 设备,通过对 mdadm 命令的主要参数来介绍软 RAID 设备的创建,删除,停止和扩展等操作,以及其元数据和位图 bitmap 数据的管理方法。在本文中我们讨论使用软 RAID 设备常见的问题以及解决的方法。
1. RAID 的子设备物理上要独立不相关

对一个磁盘上的多个磁盘分区做RAID是没有价值的,因为不但违背了RAID阵列中设备独立性的原则,不能增加阵列的可靠性,当这个磁盘失效后必然不可避免的导致数据丢失,而且还导致阵列的性能显著降低,当数据读写时磁头在磁盘的多个分区上来回抖动带来长时间的搜索耗时。

2. RAID 0 没有数据冗余功能

RAID 0 只能使用数据块条带化(stripping)功能来提高性能,如果有磁盘失效则会导致MD设备上的数据丢失,在读写MD设备时出错。

3. 快速测试命令

当创建磁盘时,如果已知设备上的数据已经是同步(sync)成功过,或者仅仅是用来测试阵列,可以使用–assume-clean参数来通知MD驱动不必初始化阵列。

                mdadm -C /dev/md0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh –assume-clean
            

如果想避免mdadm每次创建命令时,因为设备上还有以前的元数据的提示,避免手工输入,可以使用–run(或者其缩写-R)通知阵列直接运行。

                mdadm –create –run /dev/md0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh –assume-clean
            

4. 异构磁盘组成的RAID

RAID0可以支持不同大小的磁盘构造多个区域(zone)的RAID,每个区域有不同的磁盘个数。使用fdisk命令查询/dev/sdi1为2GB, /dev/sdj1为4GB,/dev/sdk1为1GB,所以做成RAID0设备为7GB。

               
                mdadm -C /dev/md0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh –assume-clean
            

而RAID1,RAID456, RAID10等对不同大小的磁盘只能使用最小的磁盘的容量作为公共的大小,多余的部分被浪费掉。/dev/sdi1,/dev/sdj1,/dev/sdk1做成的RAID5设备为2GB,是最小的设备/dev/sdk1的2倍,设备/dev/sdi1和sdj1分别浪费了1GB和3GB。

[root@fc5 mdadm-2.6.3]# ./mdadm –CR /dev/md1 -l0 -n3 /dev/sd[i-k]1
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md1 | grep “Array Size”
     Array Size : 7337664 (7.00 GiB 7.51 GB)

在阵列的状态信息查询中的大小(ArraySize)前面使用的是KB,也表示MD块设备的实际大小;而后面的两个值只是为了显示处理后的结果。

[root@fc5 mdadm-2.6.3]# ./mdadm –CR /dev/md1 -l0 -n3 /dev/sd[i-k]1
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md1 | grep “Array Size”
     Array Size : 7337664 (7.00 GiB 7.51 GB)
[root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md1 -l5 -n3 /dev/sd[i-k]1
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md1 | grep “Array Size”
     Array Size : 2096896 (2048.09 MiB 2147.22 MB)  

5. 配置共享的热备盘

mdadm程序是允许多个RAID组共享冗余磁盘的。 例如有/dev/md0和/dev/md1两个阵列,在创建时/dev/md0里面有一个热备磁盘,而/dev/md1没有热备磁盘。我们只要在/etc/mdadm.conf中配置两个阵列使用相同的spare-group组。

[root@fc5 mdadm-2.6.3]# cat /etc/mdadm.conf
DEVICE /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg /dev/sdh
       /dev/sdi1 /dev/sdj1 /dev/sdk1
ARRAY /dev/md1 level=raid0 num-devices=3 spare-group=sparedisks
      UUID=dcff6ec9:53c4c668:58b81af9:ef71989d
ARRAY /dev/md0 level=raid10 num-devices=6 spare-group=sparedisks
      UUID=0cabc5e5:842d4baa:e3f6261b:a17a477a      

并运行mdadm 的监控(monitor)模式命令。当/dev/md1阵列中的一个磁盘/dev/sdi1失效时,mdadm会自动从/dev/md0组中上移走spare磁盘,并加入/dev/md1中。

[root@fc5 mdadm-2.6.3]#./mdadm –monitor –mail=root@localhost –syslog –program=/root/md.sh
                     –delay=300 /dev/md* –daemonise
8105
[root@fc5 mdadm-2.6.3]#./mdadm /dev/md1 -f /dev/sdi1
mdadm: set /dev/sdi1 faulty in /dev/md1
[root@fc5 mdadm-2.6.3]#./mdadm -D /dev/md1
/dev/md1:
        Version : 00.90.03
  Creation Time : Mon Aug 23 00:10:00 1999
     Raid Level : raid5
     Array Size : 2096896 (2048.09 MiB 2147.22 MB)
  Used Dev Size : 1048448 (1024.05 MiB 1073.61 MB)
   Raid Devices : 3
  Total Devices : 4
Preferred Minor : 1
    Persistence : Superblock is persistent

    Update Time : Mon Aug 23 00:13:15 1999
          State : clean, degraded, recovering
Active Devices : 2
Working Devices : 3
Failed Devices : 1
  Spare Devices : 1

         Layout : left-symmetric
     Chunk Size : 64K

Rebuild Status : 78% complete

           UUID : 34d3de75:6912dc24:e1316607:4e72cd01
         Events : 0.4

    Number   Major   Minor   RaidDevice State
       3       8      112        0      spare rebuilding   /dev/sdh
       1       8      145        1      active sync   /dev/sdj1
       2       8      161        2      active sync   /dev/sdk1

       4       8      129        -      faulty spare   /dev/sdi1

6. 多种元数据格式

目前MD设备有两种主要的元数据格式(0.9版本和1.x版本),主要是元数据占用的空间不同和支持的底层设备个数不同,而且1.x版本还可以指定元数据写入设备的具体位置(1.0为在设备尾部,1.1为在设备开始,1.2为在设备开始的4KB位置)。创建阵列通过–metadata(或者其缩写-e)参数来指定元数据格式版本。

[root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md0 -l5 -n6 -x1  /dev/sd[b-h]
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0 | grep Version
        Version : 00.90.03
[root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md0 -l5 -n6 -x1 -e1.0 /dev/sd[b-h]
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0 | grep Version
        Version : 01.00.03
[root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md0 -l5 -n6 -x1 -e1.1 /dev/sd[b-h]
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0 | grep Version
        Version : 01.01.03
[root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md0 -l5 -n6 -x1 -e1.2 /dev/sd[b-h]
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0 | grep Version
        Version : 01.02.03  

当阵列将磁盘移走后,也使用–zero-superblock清空设备上面的元数据信息。

[root@fc5 mdadm-2.6.3]# ./mdadm -Es /dev/sdh
ARRAY /dev/md0 level=raid5 num-devices=6
UUID=acd2b182:4695ee20:37689502:eb0423e1
   spares=1
[root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 -f  /dev/sdh -r /dev/sdh
mdadm: set /dev/sdh faulty in /dev/md0
mdadm: hot removed /dev/sdh
[root@fc5 mdadm-2.6.3]# ./mdadm –zero-superblock /dev/sdh
[root@fc5 mdadm-2.6.3]# ./mdadm -Es /dev/sdh
[root@fc5 mdadm-2.6.3]#  

7. 可分区的RAID设备

如果想对支持分区的MD设备(Partitionable raid array)进行分区,需要在创建时使用/dev/md_d0来替代前面的/dev/md0。创建阵列是通过–auto=mdp(或者其缩写-ap)参数指定。

[root@fc5 mdadm-2.6.3]# ./mdadm -Cv –auto=mdp /dev/md_d0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh
mdadm: layout defaults to left-symmetric
mdadm: chunk size defaults to 64K
mdadm: size set to 1048512K
mdadm: array /dev/md_d0 started.
[root@fc5 mdadm-2.6.3]# fdisk /dev/md_d0
Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only,
until you decide to write them. After that, of course, the previous
content won’t be recoverable.

The number of cylinders for this disk is set to 1310640.
There is nothing wrong with that, but this is larger than 1024,
and could in certain setups cause problems with:
1) software that runs at boot time (e.g., old versions of LILO)
2) booting and partitioning software from other OSs
   (e.g., DOS FDISK, OS/2 FDISK)
Warning: invalid flag 0×0000 of partition table 4 will be corrected by w(rite)

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 1
First cylinder (1-1310640, default 1):1
Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-1310640, default 1310640): +1024M

Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
First cylinder (250002-1310640, default 250002):250002
Using default value 250002
Last cylinder or +size or +sizeM or +sizeK (250002-1310640, default 1310640):1310640
Using default value 1310640

Command (m for help): w
The partition table has been altered!

Calling ioctl() to re-read partition table.
Syncing disks.
[root@fc5 mdadm-2.6.3]# fdisk -l /dev/md_d0

Disk /dev/md_d0: 5368 MB, 5368381440 bytes
2 heads, 4 sectors/track, 1310640 cylinders
Units = cylinders of 8 * 512 = 4096 bytes

      Device Boot      Start         End      Blocks   Id  System
/dev/md_d0p1               1      250001     1000002   83  Linux
/dev/md_d0p2          250002     1310640     4242556   83  Linux

MD设备支持两种块设备,一种是不可分区类型的名字是md设备,主设备号是9,另一种是可分区的名字是mdp设备,mdp的主设备号是动态分配的,一个mdp设备最多能支持63个分区。查看/proc/device信息能看到mdp的主设备号,查询/proc/partitions信息能看到md和mdp设备的主设备号和从设备号。

[root@fc5 mdadm-2.6.3]# cat /proc/devices | grep md
1 ramdisk
9 md
253 mdp
[root@fc5 mdadm-2.6.3]# cat /proc/partitions | grep md
   9     1    2096896 md1
253     0    5242560 md_d0
253     1    1000002 md_d0p1
253     2    1000002 md_d0p2

8. 怎样扩展RAID设备

Grow模式中的容量扩展(resize)功能不但支持设备大小增加,也可以支持设备大小减少,但要求使用者自己来保证MD设备有效数据上不被截断导致丢失。

[root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 –grow –size=102400
[root@fc5 mdadm-2.6.3]# ./mdadm -Q /dev/md0
/dev/md0: 600.00MiB raid5 7 devices, 0 spares. Use mdadm –detail for more detail.

而磁盘个数扩展(reshape)功能不支持设备个数减少,如果在阵列中空闲的热备盘而且也没有指定backup文件,则不能扩展。如果对于RAID5阵列有备份(backup)文件可以支持扩展一个磁盘,扩展后的磁盘阵列是降级模式的,不支持扩展多个磁盘或者对降级的RAID5阵列再扩展。这些扩展模式不够安全,仅仅是暂时没有热备盘的权宜之计,一般合理的操作还是先增加空闲的热备磁盘再执行扩展命令。

[root@fc5 mdadm-2.6.3]# ./mdadm –grow /dev/md0 -n6
mdadm: /dev/md0: Cannot reduce number of data disks (yet).
[root@fc5 mdadm-2.6.3]# ./mdadm –grow /dev/md0 -n8
mdadm: Need to backup 2688K of critical section.
mdadm: /dev/md0: Cannot grow – need a spare or backup-file to backup critical section
[root@fc5 mdadm-2.6.3]# ./mdadm -G /dev/md0 -n9 –backup-file=/root/bak-reshape
mdadm: Need to backup 1024K of critical section..
mdadm: /dev/md0: failed to initiate reshape

[root@fc5 mdadm-2.6.3]# ./mdadm -G /dev/md0 -n8 –backup-file=/root/bak-reshape
mdadm: Need to backup 2688K of critical section..
mdadm: … critical section passed.
[root@fc5 mdadm-2.6.3]#  cat /proc/mdstat
Personalities : [raid0] [raid10] [raid6] [raid5] [raid4]
md0 : active raid5 sdh[6] sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
      6291072 blocks super 0.91 level 5, 64k chunk, algorithm 2 [8/7] [UUUUUUU_]
      [>..................]  reshape =  2.6% (28608/1048512) finish=4.1min speed=4086K/sec
md1 : active raid0 sdk1[2] sdj1[1] sdi1[0]
      7337664 blocks 64k chunks

unused devices: < none >
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0
/dev/md0:
        Version : 00.91.03
  Creation Time : Sun Aug 22 23:46:29 1999
     Raid Level : raid5
     Array Size : 6291072 (6.00 GiB 6.44 GB)
  Used Dev Size : 1048512 (1024.11 MiB 1073.68 MB)
   Raid Devices : 8
  Total Devices : 7
Preferred Minor : 0
    Persistence : Superblock is persistent

    Update Time : Sun Aug 22 23:46:56 1999
          State : clean, degraded, recovering
Active Devices : 7
Working Devices : 7
Failed Devices : 0
  Spare Devices : 0

         Layout : left-symmetric
     Chunk Size : 64K

Reshape Status : 4% complete
  Delta Devices : 1, (7->8)

           UUID : 50e886b9:9e28d243:a7f6457d:5eb47f2e
         Events : 0.94

    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sdb
       1       8       32        1      active sync   /dev/sdc
       2       8       48        2      active sync   /dev/sdd
       3       8       64        3      active sync   /dev/sde
       4       8       80        4      active sync   /dev/sdf
       5       8       96        5      active sync   /dev/sdg
       6       8      112        6      active sync   /dev/sdh
       7       0        0        7      removed
[root@fc5 mdadm-2.6.3]# cat /proc/mdstat
Personalities : [raid0] [raid10] [raid6] [raid5] [raid4]
md0 : active raid5 sdh[6] sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
      7339584 blocks level 5, 64k chunk, algorithm 2 [8/7] [UUUUUUU_]

md1 : active raid0 sdk1[2] sdj1[1] sdi1[0]
      7337664 blocks 64k chunks

unused devices: < none >
[root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0
/dev/md0:
        Version : 00.90.03
  Creation Time : Sun Aug 22 23:46:29 1999
     Raid Level : raid5
     Array Size : 7339584 (7.00 GiB 7.52 GB)
  Used Dev Size : 1048512 (1024.11 MiB 1073.68 MB)
   Raid Devices : 8
  Total Devices : 7
Preferred Minor : 0
    Persistence : Superblock is persistent

    Update Time : Sun Aug 22 23:50:18 1999
          State : clean, degraded
Active Devices : 7
Working Devices : 7
Failed Devices : 0
  Spare Devices : 0

         Layout : left-symmetric
     Chunk Size : 64K

           UUID : 50e886b9:9e28d243:a7f6457d:5eb47f2e
         Events : 0.766

    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sdb
       1       8       32        1      active sync   /dev/sdc
       2       8       48        2      active sync   /dev/sdd
       3       8       64        3      active sync   /dev/sde
       4       8       80        4      active sync   /dev/sdf
       5       8       96        5      active sync   /dev/sdg
       6       8      112        6      active sync   /dev/sdh
       7       0        0        7      removed
[root@fc5 mdadm-2.6.3]# ./mdadm -G /dev/md0 -n9 –backup-file=/root/bak-reshape
mdadm: Need to backup 3584K of critical section..
mdadm: /dev/md0: failed to find device 7. Array might be degraded.
–grow aborted  

9. 为什么不能扩展RAID设备

当使用grow模式时,如果内核不支持sysfs或者MD驱动版本较低不支持时则会返回错误。另外使用strace命令跟踪能导致在哪个函数调用上出错返回。

[root@fc5 mdadm-2.6.3]# ./mdadm –grow /dev/md0 -n6
mdadm: Need to backup 1280K of critical section..
mdadm: /dev/md0: Cannot get array details from sysfs

如果系统没有加载sysfs,需要使用mount命令加载。

                mount –t sysfs sysfs /sys/
            

10. 为什么不能停止MD设备

当停止MD阵列时,有时被返回MD设备正在被使用错误,需要检查MD设备被哪个上层设备使用。一个情况是被文件系统使用,如已经被mount起来:

[root@fc5 mdadm-2.6.3]# df -h | grep md
/dev/md0              485M   11M  449M   3% /mnt/md-test

另一种情况是MD设备被用户层其他程序打开使用,如nbd-server导出MD设备:

[root@fc5 md0]#fuser -u /dev/md0
/dev/md0:             3507(root)
[root@fc5 md0]#ps ax| grep 3507
3507 ?

还有可能是内核驱动程序打开使用,如被LVM程序当作物理卷(PV)使用:

[root@fc5 mdadm-2.6.3]# ls -l /sys/block/md0/holders/
total 0
lrwxrwxrwx 1 root root 0 08-22 23:31 dm-0 -> ../../../block/dm-0

小结

如果在软RAID使用中遇到问题不能解决,应该首先查看mdadm的帮助信息;如果还不能解决,可以到mdadm的邮件列表寻找是否有相关的问题解答或者详细描述该问题的发生过程请求大家帮助。


26
十一 07

Linux 中软件 RAID 的使用

注:转贴自 IBM
张 志斌 (linuxaid@tom.com), 软件工程师, 软件工程师

在以数据为中心的信息时代,如何妥善有效地保护数据是存储系统的核心问题之一。人们可以忍受计算机宕机,所有应用程序重新启动或者硬件损坏,但是他们要求信息永远不会丢失。冗余磁盘阵列(Redundant Array of Independent Disks )技术是各种企业信息系统和个人广泛使用的解决方案,一般的中高档服务器多使用硬件RAID控制器,但是由于硬件RAID控制器的价格昂贵,导致系统成本大大增加。而随着处理器的性能快速发展,使得软件RAID的解决方法得到人们的重视。这里我们主要介绍在Linux系统中软件RAID的配置和使用方法,它既降低了系统的总投资,也能满足系统应用的需要。
一.简介

在Linux系统中目前以MD (Multiple Devices)虚拟块设备的方式实现软件RAID,利用多个底层的块设备虚拟出一个新的虚拟块设备,并且利用条带化(stripping)技术将数据块均匀分布到多个磁盘上来提高虚拟设备的读写性能,利用不同的数据冗余算法来保护用户数据不会因为某个块设备的故障而完全丢失,而且还能在设备被替换后将丢失的数据恢复到新的设备上。关于不同冗余级别的定义和数据块以及校验块的分布示意图可以参考存储专业委员会给出的参考资料“Common RAID Disk Data Format Specification ”。目前MD支持linear, multipath, raid0 (stripping), raid1 (mirror), raid4, raid5, raid6, raid10等不同的冗余级别和组成方式,当然也能支持多个RAID阵列的层叠组成raid1+0, raid5+1等类型的阵列。在参考资料“Software RAID HOWTO”中介绍了早期软件RAID阵列功能特点和使用方式,但是因为软件RAID程序的功能不断增加,因此很有必要写份新的使用介绍。

本文主要先讲解用户层mdadm如何管理软件RAID以及使用中经常遇到的问题和解决方法。在流行的Linux的发布版中,如FedoraCore,Gentoo, Ubuntu,Debian,SuseLinux系统中一般已经将MD驱动模块直接编译到内核中或编译为可动态加载的驱动模块。我们可以在机器启动后通过cat /proc/mdstat看内核是否已经加载MD驱动或者cat /proc/devices是否有md块设备,并且可以使用lsmod看MD是否是以模块形式加载到系统中。

[root@fc5 mdadm-2.6.3]# cat /proc/mdstat
Personalities :
unused devices: <none>
[root@fc5 mdadm-2.6.3]# cat /proc/devices | grep md
1 ramdisk
9 md
253 mdp
[root@fc5 mdadm-2.6.3]# lsmod | grep md
md_mod                 73364  0

如果Linux系统既没有将MD编译到内核也没有自动加载MD模块,则没有/proc/mdstat文件,那么需要执行命令modprobe md加载驱动模块。

[root@fc5 mdadm-2.6.3]#cat /proc/mdstat
cat: /proc/mdstat: No such file or directory
[root@fc5 mdadm-2.6.3]# modprobe  md
[root@fc5 mdadm-2.6.3]# lsmod | grep md
md_mod               73364  0

如果系统中没有MD驱动模块则需要自己从Linux内核源代码网站下载源代码包,并且重新编译内核,并且需要在内核的配置文件选择。

  • Multiple devices driver support (RAID and LVM)
    <*>    RAID support                                       
        <M>     Linear (append) mode  
        <M>     RAID-0 (striping) mode  
        <M>     RAID-1 (mirroring) mode
        <M>     RAID-10 (mirrored striping) mode (EXPERIMENTAL)
        <M>     RAID-4/RAID-5/RAID-6 mode
       
  •        Support adding drives to a raid-5 array
        <M>     Multipath I/O support
        <M>     Faulty test module for MD在Linux系统中用户层以前使用raidtool工具集 来管理MD设备,目前广泛使用mdadm软件来管理MD设备,而且该软件都会集成在Linux的发布版中。如果系统中没有安装可以到RAID驱动程序和mdadm软件的维护者Neil Brown的个人网站 来下载源码包进行编译安装,或者下载RPM包直接安装。mdadm的最新版本是2.6.3。可以使用mdadm –version查看当前系统使用的版本。本文使用的是mdadm-2.6.3, Linux内核版本是Linux-2.6.22.1。下面的测试命令是在虚拟机环境中测试运行的。

    [root@fc5 mdadm-2.6.3]# uname -r
    2.6.22.1
    [root@fc5 mdadm-2.6.3]# ./mdadm –version
    mdadm – v2.6.3 – 20th August 2007

    二. mdadm管理软RAID阵列

    mdadm程序是一个独立的程序,能完成所有的软RAID管理功能,主要有7种使用模式:

    模式名字 主要功能
    Create 使用空闲的设备创建一个新的阵列,每个设备具有元数据块
    Assemble 将原来属于一个阵列的每个块设备组装为阵列
    Build 创建或组装不需要元数据的阵列,每个设备没有元数据块
    Manage 管理已经存储阵列中的设备,比如增加热备磁盘或者设置某个磁盘失效,然后从阵列中删除这个磁盘
    Misc 报告或者修改阵列中相关设备的信息,比如查询阵列或者设备的状态信息
    Grow 改变阵列中每个设备被使用的容量或阵列中的设备的数目
    Monitor 监控一个或多个阵列,上报指定的事件

    2.1 为磁盘划分分区

    如果MD驱动被编译到内核中,当内核调用执行MD驱动时会自动查找分区为FD(Linux raid autodetect)格式的磁盘。所以一般会使用fdisk工具将HD磁盘或者SD磁盘分区,再设置为FD的磁盘。

    [root@fc5 mdadm-2.6.3]# fdisk /dev/sdk
    Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel
    Building a new DOS disklabel. Changes will remain in memory only,
    until you decide to write them. After that, of course, the previous
    content won’t be recoverable.

    Warning: invalid flag 0×0000 of partition table 4 will be corrected by w(rite)

    Command (m for help): n
    Command action
       e   extended
       p   primary partition (1-4)
    p
    Partition number (1-4): 1
    First cylinder (1-512, default 1):1
    Using default value 1
    Last cylinder or +size or +sizeM or +sizeK (1-512, default 512):512
    Using default value 512

    Command (m for help): t
    Selected partition 1
    Hex code (type L to list codes): FD
    Changed system type of partition 1 to fd (Linux raid autodetect)

    Command (m for help): w
    The partition table has been altered!

    Calling ioctl() to re-read partition table.
    Syncing disks.
    [root@fc5 mdadm-2.6.3]# fdisk -l /dev/sdk
    Disk /dev/sdk: 1073 MB, 1073741824 bytes
    128 heads, 32 sectors/track, 512 cylinders
    Units = cylinders of 4096 * 512 = 2097152 bytes

       Device Boot      Start         End      Blocks   Id  System
    /dev/sdk1               1         512     1048560   fd  Linux raid autodetect

    软RAID阵列实际上也可以使用任何标准的块设备作为底层设备,如SCSI设备、IDE设备、RAM disk磁盘和NBD(Network Block Device)等,甚至是其他的MD设备。

    如果MD驱动是模块形式加载,需要在系统运行时由用户层脚本控制RAID阵列启动运行。如在FedoraCore系统中在/etc/rc.d/rc.sysinit文件中有启动软RAID阵列的指令,若RAID的配置文件mdadm.conf存在,则调用mdadm检查配置文件里的选项,然后启动RAID阵列。

    echo “raidautorun /dev/md0″ | nash –quiet
    if [ -f /etc/mdadm.conf ]; then
        /sbin/mdadm -A -s
    fi

    2.2 创建新的阵列

    mdadm使用–create(或其缩写-C)参数来创建新的阵列,并且将一些重要阵列的标识信息作为元数据可以写在每一个底层设备的指定区间。–level(或者其缩写-l)表示阵列的RAID级别,–chunk(或者其缩写-c)表示每个条带单元的大小,以KB为单位,默认为64KB,条带单元的大小配置对不同负载下的阵列读写性能有很大影响。–raid-devices(或者其缩写-n)表示阵列中活跃的设备个数,而–spare-devices(或者其缩写-x)表示阵列中热备盘的个数,一旦阵列中的某个磁盘失效,MD内核驱动程序自动用将热备磁盘加入到阵列,然后重构丢失磁盘上的数据到热备磁盘上。

    创建一个RAID 0设备:
    mdadm –create  /dev/md0 –level=0 –chunk=32 –raid-devices=3 /dev/sd[i-k]1
    创建一个RAID 1设备:
    mdadm -C /dev/md0 -l1 -c128 -n2 -x1 /dev/sd[i-k]1
    创建一个RAID 5设备:
    mdadm -C /dev/md0 -l5 -n5 /dev/sd[c-g] -x1 /dev/sdb
    创建一个RAID 6设备:
    mdadm -C /dev/md0 -l6 -n5 /dev/sd[c-g] -x2 /dev/sdb /dev/sdh
    创建一个RAID 10设备:
    mdadm -C /dev/md0 -l10 -n6 /dev/sd[b-g] -x1 /dev/sdh
    创建一个RAID1+0设备:
    mdadm -C /dev/md0 -l1 -n2 /dev/sdb /dev/sdc
    mdadm -C /dev/md1 -l1 -n2 /dev/sdd /dev/sde
    mdadm -C /dev/md2 -l1 -n2 /dev/sdf /dev/sdg
    mdadm -C /dev/md3 -l0 -n3 /dev/md0 /dev/md1 /dev/md2

    当RAID1/4/5/6/10等创建成功后,需要计算每个条带的校验和信息并写入到相应磁盘上,所以RAID阵列有一个冗余组数据同步的初始化过程(resync)。但是MD设备只要创建成功后即可对外被上层应用读写使用,当然由于上层数据读写降低数据同步的性能。初始化的时间长短和磁盘阵列自身性能以及读写的应用负载相关,使用cat /proc/mdstat信息查询RAID阵列当前重构的速度和预期的完成时间。

    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid10]
    md0 : active raid10 sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          3145536 blocks 64K chunks 2 near-copies [6/6] [UUUUUU]
          [===>...........]  resync = 15.3% (483072/3145536) finish=0.3min speed=120768K/sec

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid10]
    md0 : active raid10 sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          3145536 blocks 64K chunks 2 near-copies [6/6] [UUUUUU]

    unused devices: <none>

    如果一个块设备已经正在被其他的MD设备或者文件系统使用,则不能用来创建新的MD设备。

    [root@fc5 mdadm-2.6.3]# ./mdadm -C /dev/md1 -l0 -n2 /dev/sdh /dev/sdi
    mdadm: Cannot open /dev/sdh: Device or resource busy
    mdadm: create aborted

    Build模式可以用来创建没有元数据的RAID0/1设备,不能创建RAID4/5/6/10等带有冗余级别的MD设备。

    [root@fc5 mdadm-2.6.3]# ./mdadm -BR /dev/md0 -l0 -n6 /dev/sd[b-g]
    mdadm: array /dev/md0 built and started.
    [root@fc5 mdadm-2.6.3]# ./mdadm -BR /dev/md0 -l1 -n2 /dev/sd[b-c]
    mdadm: array /dev/md0 built and started.
    [root@fc5 mdadm-2.6.3]# ./mdadm -BR /dev/md0 -l5 -n6 /dev/sd[b-g]
    mdadm: Raid level 5 not permitted with –build.
    [root@fc5 mdadm-2.6.3]# ./mdadm -BR /dev/md0 –l6 -n6 /dev/sd[b-g]
    mdadm: Raid level 5 not permitted with –build.
    [root@fc5 mdadm-2.6.3]# ./mdadm -BR /dev/md0 –l10 -n6 /dev/sd[b-g]
    mdadm: Raid level 10 not permitted with –build.

    使用阵列:

    MD设备可以像普通块设备那样直接读写,也可以做文件系统格式化。

    #mkfs.ext3 /dev/md0
    #mkdir -p /mnt/md-test
    #mount /dev/md0 /mnt/md-test

    停止正在运行的阵列:

    当阵列没有文件系统或者其他存储应用以及高级设备使用的话,可以使用–stop(或者其缩写-S)停止阵列;如果命令返回设备或者资源忙类型的错误,说明/dev/md0正在被上层应用使用,暂时不能停止,必须要首先停止上层的应用,这样也能保证阵列上数据的一致性。

    [root@fc5 mdadm-2.6.3]# ./mdadm –stop /dev/md0
    mdadm: fail to stop array /dev/md0: Device or resource busy
    [root@fc5 mdadm-2.6.3]# umount /dev/md0
    [root@fc5 mdadm-2.6.3]#./mdadm –stop /dev/md0
    mdadm: stopped /dev/md0

    2.3 组装曾创建过的阵列

    模式–assemble或者其缩写(-A)主要是检查底层设备的元数据信息,然后再组装为活跃的阵列。如果我们已经知道阵列由那些设备组成,可以指定使用那些设备来启动阵列。

    [root@fc5 mdadm-2.6.3]# ./mdadm -A /dev/md0 /dev/sd[b-h]
    mdadm: /dev/md0 has been started with 6 drives and 1 spare.

    如果有配置文件(/etc/mdadm.conf)可使用命令mdadm -As /dev/md0。mdadm先检查mdadm.conf中的DEVICE信息,然后从每个设备上读取元数据信息,并检查是否和ARRAY信息一致,如果信息一致则启动阵列。如果没有配置/etc/mdadm.conf文件,而且又不知道阵列由那些磁盘组成,则可以使用命令–examine(或者其缩写-E)来检测当前的块设备上是否有阵列的元数据信息。

    [root@fc5 mdadm-2.6.3]# ./mdadm -E /dev/sdi
    mdadm: No md superblock detected on /dev/sdi.
    [root@fc5 mdadm-2.6.3]# ./mdadm -E /dev/sdb
    /dev/sdb:
              Magic : a92b4efc
            Version : 00.90.00
               UUID : 0cabc5e5:842d4baa:e3f6261b:a17a477a
      Creation Time : Sun Aug 22 17:49:53 1999
         Raid Level : raid10
      Used Dev Size : 1048512 (1024.11 MiB 1073.68 MB)
         Array Size : 3145536 (3.00 GiB 3.22 GB)
       Raid Devices : 6
      Total Devices : 7
    Preferred Minor : 0

        Update Time : Sun Aug 22 18:05:56 1999
              State : clean
    Active Devices : 6
    Working Devices : 7
    Failed Devices : 0
      Spare Devices : 1
           Checksum : 2f056516 – correct
             Events : 0.4

             Layout : near=2, far=1
         Chunk Size : 64K

          Number   Major   Minor   RaidDevice State
    this     0       8       16        0      active sync   /dev/sdb

       0     0       8       16        0      active sync   /dev/sdb
       1     1       8       32        1      active sync   /dev/sdc
       2     2       8       48        2      active sync   /dev/sdd
       3     3       8       64        3      active sync   /dev/sde
       4     4       8       80        4      active sync   /dev/sdf
       5     5       8       96        5      active sync   /dev/sdg
       6     6       8      112        6      spare   /dev/sdh

    从上面命令结果可以找到阵列的唯一标识UUID和阵列包含的设备名字,然后再使用上面的命令来组装阵列,也可以使用UUID标识来组装阵列。没有一致的元数据的信息设备(例如/dev/sda和/dev/sda1等)mdadm程序会自动跳过。

    [root@fc5 mdadm-2.6.3]# ./mdadm -Av –uuid=0cabc5e5:842d4baa:e3f6261b:a17a477a
                                 /dev/md0 /dev/sd*
    mdadm: looking for devices for /dev/md0
    mdadm: no recogniseable superblock on /dev/sda
    mdadm: /dev/sda has wrong uuid.
    mdadm: no recogniseable superblock on /dev/sda1
    mdadm: /dev/sda1 has wrong uuid.
    mdadm: no RAID superblock on /dev/sdi
    mdadm: /dev/sdi has wrong uuid.
    mdadm: /dev/sdi1 has wrong uuid.
    mdadm: no RAID superblock on /dev/sdj
    mdadm: /dev/sdj has wrong uuid.
    mdadm: /dev/sdj1 has wrong uuid.
    mdadm: no RAID superblock on /dev/sdk
    mdadm: /dev/sdk has wrong uuid.
    mdadm: /dev/sdk1 has wrong uuid.
    mdadm: /dev/sdb is identified as a member of /dev/md0, slot 0.
    mdadm: /dev/sdc is identified as a member of /dev/md0, slot 1.
    mdadm: /dev/sdd is identified as a member of /dev/md0, slot 2.
    mdadm: /dev/sde is identified as a member of /dev/md0, slot 3.
    mdadm: /dev/sdf is identified as a member of /dev/md0, slot 4.
    mdadm: /dev/sdg is identified as a member of /dev/md0, slot 5.
    mdadm: /dev/sdh is identified as a member of /dev/md0, slot 6.
    mdadm: added /dev/sdc to /dev/md0 as 1
    mdadm: added /dev/sdd to /dev/md0 as 2
    mdadm: added /dev/sde to /dev/md0 as 3
    mdadm: added /dev/sdf to /dev/md0 as 4
    mdadm: added /dev/sdg to /dev/md0 as 5
    mdadm: added /dev/sdh to /dev/md0 as 6
    mdadm: added /dev/sdb to /dev/md0 as 0
    mdadm: /dev/md0 has been started with 6 drives and 1 spare.

    配置文件:

    /etc/mdadm.conf作为默认的配置文件,主要作用是方便跟踪软RAID的配置,尤其是可以配置监视和事件上报选项。Assemble命令也可以使用–config(或者其缩写-c)来指定配置文件。我们通常可以如下命令来建立配置文件。

    [root@fc5 mdadm-2.6.3]#echo DEVICE /dev/sd[b-h] /dev/sd[i-k]1 > /etc/mdadm.conf
    [root@fc5 mdadm-2.6.3]# ./mdadm -Ds >>/etc/mdadm.conf
    [root@fc5 mdadm-2.6.3]# cat /etc/mdadm.conf
    DEVICE /dev/sdb /dev/sdc /dev/sdd /dev/sde /dev/sdf /dev/sdg /dev/sdh
                 /dev/sdi1 /dev/sdj1 /dev/sdk1
    ARRAY /dev/md1 level=raid0 num-devices=3
    UUID=dcff6ec9:53c4c668:58b81af9:ef71989d
    ARRAY /dev/md0 level=raid10 num-devices=6 spares=1
    UUID=0cabc5e5:842d4baa:e3f6261b:a17a477a

    使用配置文件启动阵列时,mdadm会查询配置文件中的设备和阵列内容,然后启动运行所有能运行RAID阵列。如果指定阵列的设备名字,则只启动对应的阵列。

    [root@fc5 mdadm-2.6.3]# ./mdadm -As
    mdadm: /dev/md1 has been started with 3 drives.
    mdadm: /dev/md0 has been started with 6 drives and 1 spare.
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid0] [raid10]
    md0 : active raid10 sdb[0] sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1]
          3145536 blocks 64K chunks 2 near-copies [6/6] [UUUUUU]

    md1 : active raid0 sdi1[0] sdk1[2] sdj1[1]
          7337664 blocks 32k chunks

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm -S /dev/md0 /dev/md1
    mdadm: stopped /dev/md0
    mdadm: stopped /dev/md1
    [root@fc5 mdadm-2.6.3]# ./mdadm -As /dev/md0
    mdadm: /dev/md0 has been started with 6 drives and 1 spare.
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid0] [raid10]
    md0 : active raid10 sdb[0] sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1]
          3145536 blocks 64K chunks 2 near-copies [6/6] [UUUUUU]

    unused devices: <none>

    2.4 查询阵列的状态

    我们可以通过cat /proc/mdstat信息查看所有运行的RAID阵列的状态,在第一行中首先是MD的设备名,active和inactive选项表示阵列是否能读写,接着是阵列的RAID级别,后面是属于阵列的块设备,方括号[]里的数字表示设备在阵列中的序号,(S)表示其是热备盘,(F)表示这个磁盘是faulty状态。在第二行中首先是阵列的大小,单位是KB,接着是chunk-size的大小,然后是layout类型,不同RAID级别的layout类型不同,[6/6]和[UUUUUU]表示阵列有6个磁盘并且6个磁盘都是正常运行的,而[5/6]和[_UUUUU] 表示阵列有6个磁盘中5个都是正常运行的,下划线对应的那个位置的磁盘是faulty状态的。

    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4] [raid1]
    md0 : active raid5 sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 -f /dev/sdh /dev/sdb
    mdadm: set /dev/sdh faulty in /dev/md0
    mdadm: set /dev/sdb faulty in /dev/md0
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4] [raid1]
    md0 : active raid5 sdh[6](F) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[7](F)
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/5] [_UUUUU]

    unused devices: <none>

    如果Linux系统目前支持sysfs也可以访问/sys/block/md0目录查询阵列信息。

    [root@fc5 mdadm-2.6.3]# ls -l /sys/block/md0/
    capability  holders  range      size    stat       uevent
    dev         md       removable  slaves  subsystem
    [root@fc5 mdadm-2.6.3]# ls /sys/block/md0/md/
    array_state      dev-sdg           rd1               suspend_lo
    bitmap_set_bits  dev-sdh           rd2               sync_action
    chunk_size       layout            rd3               sync_completed
    component_size   level             rd4               sync_speed
    dev-sdb          metadata_version  rd5               sync_speed_max
    dev-sdc          mismatch_cnt      reshape_position  sync_speed_min
    dev-sdd          new_dev           resync_start
    dev-sde          raid_disks        safe_mode_delay
    dev-sdf          rd0               suspend_hi
    [root@fc5 mdadm-2.6.3]# ls /sys/block/md0/slaves/
    sdb  sdc  sdd  sde  sdf  sdg  sdh

    我们也可以通过mdadm命令查看指定阵列的简要信息(使用–query或者其缩写-Q)和详细信息(使用–detail或者其缩写-D) 详细信息包括RAID的版本、创建的时间、RAID级别、阵列容量、可用空间、设备数量、超级块状态、更新时间、UUID信息、各个设备的状态、RAID算法级别类型和布局方式以及块大小等信息。设备状态信息分为active, sync, spare, faulty, rebuilding, removing等等。

    [root@fc5 mdadm-2.6.3]# ./mdadm –query /dev/md0
    /dev/md0: 2.100GiB raid10 6 devices, 1 spare. Use mdadm –detail for more detail.
    [root@fc5 mdadm-2.6.3]# ./mdadm –detail /dev/md0
    /dev/md0:
            Version : 00.90.03
      Creation Time : Sun Aug 22 17:49:53 1999
         Raid Level : raid10
         Array Size : 3145536 (3.00 GiB 3.22 GB)
      Used Dev Size : 1048512 (1024.11 MiB 1073.68 MB)
       Raid Devices : 6
      Total Devices : 7
    Preferred Minor : 0
        Persistence : Superblock is persistent

        Update Time : Sun Aug 22 21:55:02 1999
              State : clean
    Active Devices : 6
    Working Devices : 7
    Failed Devices : 0
      Spare Devices : 1

             Layout : near=2, far=1
         Chunk Size : 64K

               UUID : 0cabc5e5:842d4baa:e3f6261b:a17a477a
             Events : 0.122

        Number   Major   Minor   RaidDevice State
           0       8       16        0      active sync   /dev/sdb
           1       8       32        1      active sync   /dev/sdc
           2       8       48        2      active sync   /dev/sdd
           3       8       64        3      active sync   /dev/sde
           4       8       80        4      active sync   /dev/sdf
           5       8       96        5      active sync   /dev/sdg

           6       8      112        -      spare   /dev/sdh

    2.5 管理阵列

    mdadm可以在Manage模式下,对运行中的阵列进行添加及删除磁盘。常用于标识failed磁盘,增加spare(热备)磁盘,以及从阵列中移走已经失效的磁盘等等。使用–fail(或者其缩写-f)指定磁盘损坏。

    [root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 –fail /dev/sdb
    mdadm: set /dev/sdb faulty in /dev/md0

    当磁盘已经损坏时,使用–remove(或者其缩写–f)参数将这个磁盘从磁盘阵列中移走;但如果设备还正在被阵列使用,则不能从阵列中移走。

    [root@fc5 mdadm-2.6.3]# ./mdadm  /dev/md0 –remove /dev/sdb
    mdadm: hot removed /dev/sdb
    [root@fc5 mdadm-2.6.3]# ./mdadm  /dev/md0 –remove /dev/sde
    mdadm: hot remove failed for /dev/sde: Device or resource busy

    如果阵列带有spare磁盘,那么自动将损坏磁盘上的数据重构到新的spare磁盘上;

    [root@fc5 mdadm-2.6.3]# ./mdadm -f /dev/md0 /dev/sdb ; cat /proc/mdstat
    mdadm: set /dev/sdb faulty in /dev/md0
    Personalities : [raid0] [raid10]
    md0 : active raid10 sdh[6] sdb[7](F) sdc[0] sdg[5] sdf[4] sde[3] sdd[2]
          3145536 blocks 64K chunks 2 near-copies [6/5] [U_UUUU]
          [=======>........]  recovery = 35.6% (373888/1048512) finish=0.1min speed=93472K/sec

    unused devices: <none>

    如果阵列没有热备磁盘,可以使用–add(或者其缩写-a)参数增加热备磁盘

    [root@fc5 mdadm-2.6.3]# ./mdadm  /dev/md0 –add /dev/sdh
    mdadm: added /dev/sdh

    2.6 监控阵列

    可以使用mdadm对RAID阵列进行监控,监控程序定时查询指定的事件是否发生,然后根据配置来妥善处理。例如当阵列中的磁盘设备出现问题的时候,可以发送邮件给管理员;或者当磁盘出现问题的时候由回调程序来进行自动的磁盘替换,所有监控事件都可以记录到系统日志中。目前mdadm支持的事件有RebuildStarted, RebuildNN(NN is 20, 40, 60, or 80), RebuildFinished, Fail,FailSpare,SpareActive,NewArray, DegradedArray, MoveSpare, SparesMissing, TestMessage。

    如果配置每300秒mdadm监控进程查询MD设备一次,当阵列出现错误,会发送邮件给指定的用户,执行事件处理的程序并且记录上报的事件到系统的日志文件。使用–daemonise参数(或者其缩写-f)使程序持续在后台运行。如果要发送邮件需要sendmail程序运行,当邮件地址被配置为外网地址应先测试是否能发送出去。

    [root@fc5 mdadm-2.6.3]#./mdadm –monitor –mail=root@localhost –program=/root/md.sh
                            –syslog –delay=300 /dev/md0 –daemonise

    查看系统日志信息,可以看到哪个阵列或者阵列中的哪个设备发生过的哪些事件。

    [root@fc5 mdadm-2.6.3]# mdadm -f /dev/md0 /dev/sdb
    mdadm: set /dev/sdb faulty in /dev/md0
    [root@fc5 mdadm-2.6.3]#tail –f /var/log/messages
    Aug 22 22:04:12 fc5 mdadm: RebuildStarted event detected on md device /dev/md0
    Aug 22 22:04:12 fc5 kernel: md: using maximum available idle IO bandwidth
                    (but not more than 200000 KB/sec) for recovery.
    Aug 22 22:04:12 fc5 kernel: md: using 128k window, over a total of 1048512 blocks.
    Aug 22 22:04:14 fc5 mdadm: Fail event detected on md device /dev/md0,
                    component device /dev/sdb
    Aug 22 22:04:14 fc5 mdadm: Rebuild80 event detected on md device /dev/md0
    Aug 22 22:04:16 fc5 mdadm: RebuildFinished event detected on md device /dev/md0
    Aug 22 22:04:16 fc5 mdadm: SpareActive event detected on md device /dev/md0,
                    component device /dev/sdh
    Aug 22 22:04:16 fc5 kernel: md: md0: recovery done.

    回调程序从mdadm程序接受两个或者三个参数:事件名字,监控阵列的名字和特殊事件可能使用到的底层块设备名字。上面的事件返回的信息如下:

    Eventname: RebuildStarted  Device: /dev/md0  next:
    Eventname: Fail  Device: /dev/md0  next: /dev/sdb
    Eventname: Rebuild80  Device: /dev/md0  next:
    Eventname: RebuildFinished  Device: /dev/md0  next:
    Eventname:SpareActive  Device: /dev/md0  next: /dev/sdh

    2.7 扩展阵列

    如果在创建阵列时不想使用整个块设备,可以指定用于创建RAID阵列每个块设备使用的设备大小。

    mdadm -CR /dev/md0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh –size=102400

    然后在阵列需要扩展大小时,使用模式–grow(或者其缩写-Q)以及–size参数(或者其缩写-z) 在加上合适的大小数值就能分别扩展阵列所使用每个块设备的大小。

    [root@fc5 mdadm-2.6.3]# ./mdadm -Q /dev/md0
    /dev/md0: 500.00MiB raid5 6 devices, 1 spare. Use mdadm –detail for more detail.
    [root@fc5 mdadm-2.6.3]# ./mdadm –grow /dev/md0 –size=204800
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid0] [raid10] [raid6] [raid5] [raid4]
    md0 : active raid5 sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          1024000 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]
          [============>......]  resync = 69.6% (144188/204800) finish=0.0min speed=10447K/sec

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm -Q /dev/md0
    /dev/md0: 1000.00MiB raid5 6 devices, 1 spare. Use mdadm –detail for more detail.

    如果上面是文件系统(ext2,ext3, reiserfs),在设备大小扩展后,文件系统也要同时扩展。

    [root@fc5 mdadm-2.6.3]# df -h | grep md
    /dev/md0              485M   11M  449M   3% /mnt/md-test
    [root@fc5 mdadm-2.6.3]# ext2online /dev/md0
    [root@fc5 mdadm-2.6.3]# df -h | grep md
    /dev/md0              969M   11M  909M   2% /mnt/md-test

    mdadm还提供增加或减少阵列中设备个数的功能(reshape),使用模式—grow和 –raid-disks(或者其缩写-n)参数再加上合适的设备个数。扩展后阵列中原来的热备盘变为活跃磁盘,所以阵列的设备个数增加,阵列的大小也相应增加。

    [root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0
    /dev/md0:
            Version : 00.90.03
      Creation Time : Sun Aug 22 22:16:19 1999
         Raid Level : raid5
         Array Size : 1024000 (1000.17 MiB 1048.58 MB)
      Used Dev Size : 204800 (200.03 MiB 209.72 MB)
       Raid Devices : 6
      Total Devices : 7
    Preferred Minor : 0
        Persistence : Superblock is persistent

        Update Time : Sun Aug 22 22:23:46 1999
              State : clean
    Active Devices : 6
    Working Devices : 7
    Failed Devices : 0
      Spare Devices : 1

             Layout : left-symmetric
         Chunk Size : 64K

               UUID : 53e6395c:1af16258:087cb2a0:b66b087f
             Events : 0.12

        Number   Major   Minor   RaidDevice State
           0       8       16        0      active sync   /dev/sdb
           1       8       32        1      active sync   /dev/sdc
           2       8       48        2      active sync   /dev/sdd
           3       8       64        3      active sync   /dev/sde
           4       8       80        4      active sync   /dev/sdf
           5       8       96        5      active sync   /dev/sdg

           6       8      112        -      spare   /dev/sdh
    [root@fc5 mdadm-2.6.3]# ./mdadm –grow /dev/md0 –raid-disks=7
    mdadm: Need to backup 1920K of critical section..
    mdadm: … critical section passed.
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid0] [raid10] [raid6] [raid5] [raid4]
    md0 : active raid5 sdh[6] sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          1024000 blocks super 0.91 level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]
          [===>.............]  reshape = 19.4% (40256/204800) finish=0.7min speed=3659K/sec

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0
    /dev/md0:
            Version : 00.91.03
      Creation Time : Sun Aug 22 22:16:19 1999
         Raid Level : raid5
         Array Size : 1024000 (1000.17 MiB 1048.58 MB)
      Used Dev Size : 204800 (200.03 MiB 209.72 MB)
       Raid Devices : 7
      Total Devices : 7
    Preferred Minor : 0
        Persistence : Superblock is persistent

        Update Time : Sun Aug 22 22:26:46 1999
              State : clean, recovering
    Active Devices : 7
    Working Devices : 7
    Failed Devices : 0
      Spare Devices : 0

             Layout : left-symmetric
         Chunk Size : 64K

    Reshape Status : 25% complete
      Delta Devices : 1, (6->7)

               UUID : 53e6395c:1af16258:087cb2a0:b66b087f
             Events : 0.76

        Number   Major   Minor   RaidDevice State
           0       8       16        0      active sync   /dev/sdb
           1       8       32        1      active sync   /dev/sdc
           2       8       48        2      active sync   /dev/sdd
           3       8       64        3      active sync   /dev/sde
           4       8       80        4      active sync   /dev/sdf
           5       8       96        5      active sync   /dev/sdg
           6       8      112        6      active sync   /dev/sdh
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid0] [raid10] [raid6] [raid5] [raid4]
    md0 : active raid5 sdh[6] sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          1228800 blocks level 5, 64k chunk, algorithm 2 [7/7] [UUUUUUU]

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm -D /dev/md0
    /dev/md0:
            Version : 00.90.03
      Creation Time : Sun Aug 22 22:16:19 1999
         Raid Level : raid5
         Array Size : 1228800 (1200.20 MiB 1258.29 MB)
      Used Dev Size : 204800 (200.03 MiB 209.72 MB)
       Raid Devices : 7
      Total Devices : 7
    Preferred Minor : 0
        Persistence : Superblock is persistent

        Update Time : Sun Aug 22 22:37:11 1999
              State : clean
    Active Devices : 7
    Working Devices : 7
    Failed Devices : 0
      Spare Devices : 0

             Layout : left-symmetric
         Chunk Size : 64K

               UUID : 53e6395c:1af16258:087cb2a0:b66b087f
             Events : 0.204

        Number   Major   Minor   RaidDevice State
           0       8       16        0      active sync   /dev/sdb
           1       8       32        1      active sync   /dev/sdc
           2       8       48        2      active sync   /dev/sdd
           3       8       64        3      active sync   /dev/sde
           4       8       80        4      active sync   /dev/sdf
           5       8       96        5      active sync   /dev/sdg
           6       8      112        6      active sync   /dev/sdh

    2.8 Bitmap记录

    使用bitmap模式记录RAID阵列有多少个块已经同步(resync)。参数–bitmap(或者其缩写-b)指定记录bitmap信息的文件名,如果是interval参数表示bitmap记录在每个设备的元数据区。–bitmap-chunk表示每个bit位代表RAID设备多大的数据块,单位是KB;而–delay(或者其缩写-d)指定多长事件同步bitmap信息到文件或者设备上,单位是秒,默认是5秒。–force(或者其缩写)表示覆盖掉已经存在bitmap文件。而且使用–examine-bitmap(或者其缩写-X)能够查看存储在文件或者设备元数据中的bitmap记录的信息。

    当阵列创建时指定bitmap模式,如果阵列初始化中停止阵列,当再次启动阵列中,RAID阵列能够利用bitmap记录从上次中断的位置接着执行。

    [root@fc5 mdadm-2.6.3]# ./mdadm -CR /dev/md1 -l1 -n2 /dev/sdi1 /dev/sdj1 –bitmap=internal
    mdadm: array /dev/md1 started.
    [root@fc5 tests]# cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4] [raid1]
    md1 : active raid1 sdj1[1] sdi1[0]
          2096384 blocks [2/2] [UU]
          [========>......]  resync = 51.2% (1075072/2096384) finish=0.1min speed=153581K/sec
          bitmap: 128/128 pages [512KB], 8KB chunk

    unused devices: <none>
    [root@fc5 tests]# ./mdadm -X /dev/sdi1
            Filename : /dev/sdi1
               Magic : 6d746962
             Version : 4
                UUID : bcccddb7:0f529abd:672e1f66:7e68bbc8
              Events : 1
      Events Cleared : 1
               State : OK
           Chunksize : 8 KB
              Daemon : 5s flush period
          Write Mode : Normal
           Sync Size : 2096384 (2047.59 MiB 2146.70 MB)
              Bitmap : 262048 bits (chunks), 262048 dirty (100.0%)
    [root@fc5 tests]# ./mdadm –stop /dev/md1
    mdadm: stopped /dev/md1
    [root@fc5 tests]# ./mdadm -A /dev/md1 /dev/sd[i-k]1 –bitmap=internal ; cat /proc/mdstat
    mdadm: there is no need to specify –bitmap when assembling arrays with internal bitmaps
    mdadm: /dev/md1 has been started with 2 drives and 1 spare.
    Personalities : [raid6] [raid5] [raid4] [raid1]
    md1 : active raid1 sdi1[0] sdk1[2](S) sdj1[1]
          1048448 blocks [2/2] [UU]
          [==============>...]  resync = 87.6% (919616/1048448) finish=0.0min speed=89408K/sec
          bitmap: 27/128 pages [108KB], 4KB chunk

    unused devices: <none>
    [root@fc5 tests]# cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4] [raid1]
    md1 : active raid1 sdj1[1] sdi1[0]
          2096384 blocks [2/2] [UU]
          bitmap: 0/128 pages [0KB], 8KB chunk
    [root@fc5 tests]# mdadm -X /dev/sdi1
    unused devices: <none>
            Filename : /dev/sdi1
               Magic : 6d746962
             Version : 4
                UUID : bcccddb7:0f529abd:672e1f66:7e68bbc8
              Events : 4
      Events Cleared : 4
               State : OK
           Chunksize : 8 KB
              Daemon : 5s flush period
          Write Mode : Normal
           Sync Size : 2096384 (2047.59 MiB 2146.70 MB)
              Bitmap : 262048 bits (chunks), 0 dirty (0.0%)

    使用bitmap文件记录要求这个文件不能在RAID阵列上或者其相关的设备上,而且使用assemble命令时要指定bitmap文件名字。

    [root@fc5 mdadm-2.6.3]#./mdadm -CR /dev/md0 -l5 -n6 /dev/sd[b-g] -x1 /dev/sdh
                       –bitmap=/tmp/md0-bm –bitmap-chunk=4 –delay=1 –force
    mdadm: array /dev/md0 started.
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat ; ./mdadm -X /tmp/md0-bm
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[0]
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]
          [===========>.......]  resync = 64.3% (675748/1048512) finish=0.7min speed=7848K/sec
          bitmap: 128/128 pages [512KB], 4KB chunk, file: /tmp/md0-bm

    unused devices: <none>
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : d2f46320:40f1e154:08d7a21a:4cc9a9c1
              Events : 1
      Events Cleared : 1
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 262128 dirty (100.0%)
    [root@fc5 mdadm-2.6.3]# ./mdadm –stop /dev/md0
    mdadm: stopped /dev/md0
    [root@fc5 mdadm-2.6.3]# ./mdadm -A /dev/md0 /dev/sd[b-h] –bitmap=/tmp/md0-bm ;
                      cat /proc/mdstat ; ./mdadm -X /tmp/md0-bm
    mdadm: /dev/md0 has been started with 6 drives and 1 spare.
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdb[0] sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1]
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]
          [=============>.....]  resync = 70.5% (739884/1048512) finish=0.7min speed=6539K/sec
          bitmap: 41/128 pages [164KB], 4KB chunk, file: /tmp/md0-bm

    unused devices: <none>
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : d2f46320:40f1e154:08d7a21a:4cc9a9c1
              Events : 3
      Events Cleared : 3
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 83696 dirty (31.9%)
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat ; ./mdadm -X /tmp/md0-bm
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdb[0] sdh[6](S) sdg[5] sdf[4] sde[3] sdd[2] sdc[1]
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]
          bitmap: 0/128 pages [0KB], 4KB chunk, file: /tmp/md0-bm

    unused devices: <none>
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : d2f46320:40f1e154:08d7a21a:4cc9a9c1
              Events : 6
      Events Cleared : 6
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 0 dirty (0.0%)

    bitmap模式在阵列处于降级(degrade)状态能够记录有哪些块被写过,当那个暂时失效的磁盘使用–re-add参数被重新添加后,阵列只重构这期间修改的数据块,减少阵列重构的时间。bitmap信息中dirty的数量表示降级期间被修改过的块。

    [root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 -f /dev/sdb /dev/sdh
    mdadm: set /dev/sdb faulty in /dev/md0
    mdadm: set /dev/sdh faulty in /dev/md0
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdh[6](F) sdg[5] sdf[4] sde[3] sdd[2] sdc[1] sdb[7](F)
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/5] [_UUUUU]
          bitmap: 0/128 pages [0KB], 4KB chunk, file: /tmp/md0-bm

    unused devices: <none>
    [root@fc5 mdadm-2.6.3]# ./mdadm -X /tmp/md0-bm
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : 3ede3bc0:adb1a404:49a18eed:f1b5c89a
              Events : 8
      Events Cleared : 1
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 0 dirty (0.0%)
    [root@fc5 mdadm-2.6.3]# dd if=/dev/zero of=/dev/md0 bs=1M count=1024
    1024+0 records in
    1024+0 records out
    1073741824 bytes (1.1 GB) copied, 11.9995 seconds, 89.5 MB/s
    [root@fc5 mdadm-2.6.3]# ./mdadm -X /tmp/md0-bm
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : 3ede3bc0:adb1a404:49a18eed:f1b5c89a
              Events : 10
      Events Cleared : 1
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 52432 dirty (20.0%)
    [root@fc5 mdadm-2.6.3]# ./mdadm /dev/md0 -r /dev/sdb –re-add /dev/sdb
    [root@fc5 mdadm-2.6.3]# cat /proc/mdstat ; ./mdadm -X /tmp/md0-bm
    Personalities : [raid6] [raid5] [raid4]
    md0 : active raid5 sdb[0] sdh[6](F) sdg[5] sdf[4] sde[3] sdd[2] sdc[1]
          5242560 blocks level 5, 64k chunk, algorithm 2 [6/6] [UUUUUU]
          bitmap: 0/128 pages [0KB], 4KB chunk, file: /tmp/md0-bm

    unused devices: <none>
            Filename : /tmp/md0-bm
               Magic : 6d746962
             Version : 4
                UUID : 3ede3bc0:adb1a404:49a18eed:f1b5c89a
              Events : 24
      Events Cleared : 24
               State : OK
           Chunksize : 4 KB
              Daemon : 1s flush period
          Write Mode : Normal
           Sync Size : 1048512 (1024.11 MiB 1073.68 MB)
              Bitmap : 262128 bits (chunks), 0 dirty (0.0%)

    结束语

    mdadm管理程序和Linux内核的MD驱动程序由同一个维护者Neil Brown统一管理,因此两个软件的功能也在不断的增加,对应的软件版本也能及时升级。本文讲述了Linux系统中软RAID的基本概念和如何使用mdadm程序来管理软RAID设备,介绍了软RAID设备的创建,删除,停止和扩展等操作,以及其元数据和位图bitmap数据的管理方法。我们还将在文章”Linux中软件RAID使用常见问题解决”讨论使用软RAID设备常见的问题以及解决的方法。


  • 25
    十一 07

    MySQL Proxy

    据说MySQL Proxy可以用来实现MySQL负载均衡和读写分开。

    http://dev.mysql.com/downloads/mysql-proxy/

    http://forge.mysql.com/wiki/MySQL_Proxy


    24
    十一 07

    vi技巧整理收集

    1. 交换两个字符位置
    xp
    2. 上下两行调换
    ddp
    3. 把文件内容反转
    :g/^/m0
    4. 把DOS格式的文本文件的\r\n换行符(在UNIX显示为^M)去掉
    :%s/^M//g
    注意,^M的输入方法为:Ctrl+v,然后按一下回键。
    5. 特殊字符,Ctrl+v
    比如将}字符换成}回车
    :%s/}/}^M/g

    6.打开、关闭自动缩进

    :set autoindent

    :set noautoindent


    23
    十一 07

    NTFS也有硬链接

    windows NTFS 文件系统硬连接命令:fsutil hardlink create

    windows xp 系统有一个鲜为人知的命令: fsutil (file system util)这是一个非常强大的控制 ntfs 文件系统行为的命令,这个命令其中一个功能便是创建硬链接
    语法如下:
    fsutil hardlink create c:\foo.txt c:\bar.txt
    这样 c:\foo.txt c:\bar.txt 两个入口点便会被设置为指向同一个 ntfs 文件对象。一个用于建立硬链接的shellexthttp://dormforce.net/Blog/electronixtar/archive/2006/11/20/11685.aspx Windows上的12种快捷方式


    23
    十一 07

    利用硬连接备份

    pdumpfs是一个使用ruby语言写的备份软件。
    http://0xcc.net/pdumpfs/index.html.en

    使用ruby需要ruby环境,yum -y install ruby (CentOS 5.2)。

    pdumpfs会以YYYY/MM/DD的方式(pdumpfs以天为单位备份),自动建目录;第一次备份时,复制原目录,以后的每次备份中,pdumpfs只复制有更新的文件,不变的文件,以硬连接的方式存储在新的YYYY/MM/DD目录中,这样备份速度快,利省空间。

    pdumpfs src-dir dest-dir [dest-basename]

    cp命令的-l参数就是一个只建立硬连接,不真正复制的过程。和rsync共用,可以实现增量备份。

    glastree 1.04 (stable)

      The poor man’s daily snapshot, glastree builds live backup trees, with branches for each day. Users directly browse the past to recover older documents or retrieve lost files. Hard links serve to compress out unchanged files, while modified ones are copied verbatim. A prune utility effects a constant, sliding window.Satoru Takabayashi has writen a similar program, in Ruby, pdumpfs.

      Inspired by Plan9, of course.

      Terje Kvernes put together a gentoo ebuild.

    Links |

    README, CHANGES, CVS

    Reqs |

    Perl 5.002, Date::Calc, GNU Make

    Xfer |

    glastree-1.04.tar.gz, 14 February 2006, 6K


    23
    十一 07

    rsync 参数详解

    选项说明

    -v, –verbose 详细模式输出
    -q, –quiet 精简输出模式
    -c, –checksum 打开校验开关,强制对文件传输进行校验
    -a, –archive 归档模式,表示以递归方式传输文件,并保持所有文件属性,等于-rlptgoD
    -r, –recursive 对子目录以递归模式处理
    -R, –relative 使用相对路径信息
                   
    rsync foo/bar/foo.c remote:/tmp/

    则在/tmp目录下创建foo.c文件,而如果使用-R参数:

    rsync -R foo/bar/foo.c remote:/tmp/

    则会创建文件/tmp/foo/bar/foo.c,也就是会保持完全路径信息。

    -b, –backup 创建备份,也就是对于目的已经存在有同样的文件名时,将老的文件重新命名为~filename。可以使用–suffix选项来指定不同的备份文件前缀。
    –backup-dir 将备份文件(如~filename)存放在在目录下。
    -suffix=SUFFIX 定义备份文件前缀
    -u, –update 仅仅进行更新,也就是跳过所有已经存在于DST,并且文件时间晚于要备份的文件。(不覆盖更新的文件)
    -l, –links 保留软链结
    -L, –copy-links 想对待常规文件一样处理软链结
    –copy-unsafe-links 仅仅拷贝指向SRC路径目录树以外的链结
    –safe-links 忽略指向SRC路径目录树以外的链结
    -H, –hard-links 保留硬链结
    -p, –perms 保持文件权限
    -o, –owner 保持文件属主信息
    -g, –group 保持文件属组信息
    -D, –devices 保持设备文件信息
    -t, –times 保持文件时间信息
    -S, –sparse 对稀疏文件进行特殊处理以节省DST的空间
    -n, –dry-run现实哪些文件将被传输
    -W, –whole-file 拷贝文件,不进行增量检测
    -x, –one-file-system 不要跨越文件系统边界
    -B, –block-size=SIZE 检验算法使用的块尺寸,默认是700字节
    -e, –rsh=COMMAND 指定替代rsh的shell程序
    –rsync-path=PATH 指定远程服务器上的rsync命令所在路径信息
    -C, –cvs-exclude 使用和CVS一样的方法自动忽略文件,用来排除那些不希望传输的文件
    –existing 仅仅更新那些已经存在于DST的文件,而不备份那些新创建的文件
    –delete 删除那些DST中SRC没有的文件
    –delete-excluded 同样删除接收端那些被该选项指定排除的文件
    –delete-after 传输结束以后再删除
    –ignore-errors 及时出现IO错误也进行删除
    –max-delete=NUM 最多删除NUM个文件
    –partial 保留那些因故没有完全传输的文件,以是加快随后的再次传输
    –force 强制删除目录,即使不为空
    –numeric-ids 不将数字的用户和组ID匹配为用户名和组名
    –timeout=TIME IP超时时间,单位为秒
    -I, –ignore-times 不跳过那些有同样的时间和长度的文件
    –size-only 当决定是否要备份文件时,仅仅察看文件大小而不考虑文件时间
    –modify-window=NUM 决定文件是否时间相同时使用的时间戳窗口,默认为0
    -T –temp-dir=DIR 在DIR中创建临时文件
    –compare-dest=DIR 同样比较DIR中的文件来决定是否需要备份
    -P 等同于 –partial
    –progress 显示备份过程
    -z, –compress 对备份的文件在传输时进行压缩处理
    –exclude=PATTERN 指定排除不需要传输的文件模式
    –include=PATTERN 指定不排除而需要传输的文件模式
    –exclude-from=FILE 排除FILE中指定模式的文件
    –include-from=FILE 不排除FILE指定模式匹配的文件
    –version 打印版本信息
    –address 绑定到特定的地址
    –config=FILE 指定其他的配置文件,不使用默认的rsyncd.conf文件
    –port=PORT 指定其他的rsync服务端口
    –blocking-io 对远程shell使用阻塞IO
    -stats 给出某些文件的传输状态
    –progress 在传输时现实传输过程
    –log-format=FORMAT 指定日志文件格式
    –password-file=FILE 从FILE中得到密码
    –bwlimit=KBPS 限制I/O带宽,KBytes per second
    -h, –help 显示帮助信息


    23
    十一 07

    LVM1使用备忘

    删除vg时,提供vg被active不能删除。
    使用lvmchange -R (reset lvm)
    然后就可以删除了

    扩展lv的大小(可以在线操作,即在lv被mount的状态下操作)
    lvextend -l +10G /dev/vg0/dbslave

    接着需要扩展文件系统的大小了,ext2/ext3文件系统使用e2fsprogs软件包里的工具resize2fs
    需要在umont的状态下操作,操作之前需要先fsck文件系统
    e2fsck /dev/vg0/dbslave
    resize2fs /dev/vg0/dbslave

    在线扩展lv的文件系统,需要使用LVM带的e2fsadm工具,不过这个工具需要使用/sbin/ext2online这个工具。


    22
    十一 07

    LVM2使用备忘

    初始化配置文件
    vgscan

    建立物理卷
    pvcreate /dev/sda2
    pvcreate /dev/sda3

    建立卷组
    vgcreate  vg0 /dev/sda2

    扩展逻辑卷
    vgextend vg0 /dev/sda3

    建立逻辑卷
    lvcreate -L 60G -n lv_name  vg0

    删除逻辑卷
    lvremove /dev/vg0/lv_name

    扩充和减小逻辑卷的容量
    #e2fsadm -L +100M /dev/vg0/vg1  
    -L 表示增减空间 +表示加 -表示建
    #e2fsadm -L -100M /dev/vg0/vg1
    这里要注意文件系统必需是ext2或ext3,而且需要卸载文件系统来执行,减小的时候需要知道剪掉空间的大小,不然会造成丢失


    22
    十一 07

    编译mysql-5.0.45,支持大表,线程库支持

    BASH环境:

    export LDFLAGS=’-s’
    ./configure -q –prefix=/usr/local/mysql-5.0.45 –enable-assembler –with-charset=utf8 –with-collation=utf8_general_ci  –with-pthread  –with-embedded-server –with-mysqlmanager –with-big-tables
    make -s -j4


    21
    十一 07

    Linux服务器的最大内存和CPU数限制

    Intel X86

    .最大CPU数: 32(包括逻辑CPU)
    .最大内存: 64GB
    .最大文件大小: 8TB
    .最大文件系统大小(ext3): 16TB
    .最大每个进程的虚拟地址空间: 4GB

    AMD 64/EM64T

    .最大CPU数: 64
    .最大内存: 128GB
    .最大文件大小: 8TB
    .最大文件系统大小(ext3): 16TB
    .最大每个进程的虚拟地址空间: N/A

    请注意上面是标准的最大限制, 请不要跟Linux集群系统混淆(能扩充到1024个CPU).

    你可以从Linux内核文档/usr/src/linux/Documentation获得最新的信息.


    21
    十一 07

    教你如何构建自己的 Linux 发行版

    Linux From Scratch (LFS) 及其后代代表一种新方法,向用户揭示 Linux 操作系统是如何工作的。LFS 基于这样的假设,即一部分一部分地编译完整的操作系统不仅能够揭示操作系统是如何工作的,也允许独立的操作人员为速度、内存占用或安全性而构建系统。

    许多作家已经编写了有关 UNIX? 风格的书籍,深入研究了调度、内存管理、多进程和线程、文件系统,以及用户与内核之间的交互。写作 Linux 书籍的作家相对于 UNIX 作家来说有一个优势:尽管团体发生了剧变,但是 Linux 内核不可能分成几个相互竞争的分支,由于 GNU Public License (GPL)、集中式研究实验室 Open Source Development Lab (OSDL) 和 Linus Torvalds 不可动摇的地位,使得 Linux 有幸成为一个缓慢移动的目标(slow-moving target)。

    为什么 UNIX 内核很重要

    除了某些方面具有一定的相似性之外,不同的 Unix 内核并不怎么相同。各种 UNIX 风格也具有一个 Linux 所缺少的优点:所有 UNIX 风格都被假定是完全的操作系统。Linux 通常被描述为“只是一个内核”(如果有这样的定义的话,也是一个武断的定义),它给出公共功能和实现的核心,不管内核是运行在不太强大的 Pentium? II 机器上还是 Symmetric Multiprocessing (SMP) 系统上,这些公共功能和实现都不会发生本质上的改变。为了更加简化,有人可能会说,离 Linux 内核越远,就会发现更多的变化,而 UNIX 系统则趋向于是各种 UNIX/POSIX 标准的离散实现。

    事情并没有这么简单。检测 Linux 内核和系统级代码可能是一件很费时间的事情,并且在现实世界中会限制使用。LFS 项目旨在解决 Linux 上有限的系统级可理解性问题。关于内核需要大量的库和工具来让 Linux 系统执行最基本的任务这一事实,已经做过讨论了,但是如果一个比较熟练的用户具有一个 slim-line Linux 发行版,他不想下载几吉字节不让他优化系统、也不让他抛开所有这些麻烦且不必要的工具的二进制代码,那该怎么办?如果一个非常熟练的用户拒绝接受各种社团发行版的 苛刻条件(diktat),而想要运行一个来自 CD 的 Linux/Apache/MySQL/PHP (LAMP) 类型的应用程序堆栈,那该怎么办?LFS 可以解决这些问题。

    Linux From Scratch

    LFS 项目显然建立于那些对于构成基本的 Linux 系统来说充分而不必要的源文件的基础之上。它已经超越了 Linux 内核和设备驱动程序,因为要产生一个可工作的 Linux 系统,您必须添加一个完整的编译器工具链、许多 Linux 汇编程序实用工具、glibc 系统库、系统配置工具和连接到 userland shell 访问的工具。LFS 建立在这样一个假设的基础之上,即 Linux 或 UNIX 允许具有一些脚本编写知识的用户,了解一个完全有用的系统的工作方式,而不用深入研究内核代码本身。

    为了了解 Linux 系统的工作方式,LFS 的创建者们确定,通过遵循模块依赖性来编译系统,可能是了解一般操作系统和特定的 Linux 的机制最自然的方式。用户掌握了编译过程之后,就可以开始消除依赖性树的那些连接到与支持操作系统基本目的无关的系统组件的部件。例如,在编译完成之后,消除编译器工具链本身是可行的。在没有全套的命令行实用工具时,可以凑合使用嵌入式 LAMP 堆栈。配置实用工具也可以被丢弃,大多数用户可以凑合着用一个而不是太多 Linux 将会支持的文件系统。

    Linux 部件

    LFS 系统的一个重要部件是,可以作为 tar ball 得到的大量源文件。文档是另一个重要部件,并且是最重要的。实际上,很有可能利用一个最新的 LFS 书籍文件并创建一个 LFS 发行版,因为 LFS 书籍中详细描述了每个下载位置和每个源文件及其依赖性的特征。用于从内核到编译器到 shell 编译每组源文件的过程都是已经写好了的,如果可能,您也可以在描述具有不同特征的系统的 LFS 书籍中找到替代的例程。LFS 系统的另一个不太可能出现在一般用户工具箱中的部件是,在基本 LFS 系统组合在一起之后引导系统所需的引导脚本。

    现在对 LFS 发行版的最大警告是:勇敢的发行版构建者所需的是一个可工作的 Linux 发行版,包括一个完整的编译器工具链和一套文件系统创建实用工具。自然,所有基于源代码的 Linux 发行版都需要使用各个发行版都完全不同的特定编译器版本来引导。LFS 不是该领域的惟一系统,但它是惟一允许您直接处理单个源文件的系统。大多数其他基于源代码的 Linux 系统,比如 Sourcemage 和 MyGeOS,提供一个完整的下载,建议用户使用。LFS 不作这样的假设,并且鼓励拆开 LFS 框架。

    预先假设起作用的 Linux 发行版已安装在非外来的(nonexotic)硬件上,即使 LFS 可能没有配置工具和脚本那么受关注。要编译 LFS,您需要准备一个分区和一个文件系统,还需要编译一个编译器和系统库。如果用手工完成的话,这是一个相当伤脑筋的过程,但是也的确可以增加您在处理其余安装方面的自信。整个系统的编译要花一小时到四天的时间,具体时间取决于底层硬件的年代和您的命令行技术熟练程度。

    作一个相当大的假设,如果您愿意很大程度上保留书籍安装,并使对 LFS 书籍中提议的安装的更改保持最小,您也可以使用自动化的安装例程来安装基于 LFS 的发行版。安装例程没有在 LFS 书籍中给出,但是可以在名称 Automated Linux from Scratch (ALFS) 之下作为基于 XML 的发行版得到。活动安装可以作为基于 C 的脚本得到,该脚本使用 ncurses 来模拟图形安装。该安装也叫做 nALFS 并给出一个极为灵活的包安装框架。工作需要一个起作用的 Linux 系统,并带有可以工作的 C 编译器和 XML 解析器。一个可以工作的 LFS 系统就足够了。

    Automated Linux From Scratch

    ALFS 的目的是超越 LFS 本身。LFS 自己指导基于 Linux 的操作系统的内部工作,但是它不具有单个图形用户界面 (GUI)。 LFS 既不允许连接到网络,也不允许连接到 Internet。ALFS 可以简化系统的扩展,例如,通过添加支持 Internet 访问的库,或者通过安装图形桌面所需的 X 库。

    超越 LFS

    LFS 的创建者们认识到了对其他各种基于源代码的 Linux 系统的需求。为了这些想要超越 LFS 并添加 X Window System、 GNOME 和网络支持的人,创建了另一个 LFS 派生物:Beyond Linux From Scratch (BLFS)。第三版 LFS 书籍(让我们不会忘记是在谈论书籍而非发行版),形成一个以一个角为基础的三角形:对于自动化编译和完全的基于源代码的 Linux 发行版,基本的 LFS 版本是基础。BLFS 将基本的 Linux 系统转化成一个完全的用户广泛接受的 Linux 系统。AFLS 简化基于源代码的 Linux 安装的安装和扩展。整个基于源代码的系统的编译是由一个脚本指导的,您在针对运行脚本的硬件调整脚本之后,就可以让脚本自己运行了。在您(或安装工程师)确定需要运行哪些包,也即特定的办公应用程序套件之后,您就可以容易地扩展安装顺序了。ALFS 也迟早会派上用场,因为它适用于从源代码进行网络范围的安装。

    Hardened LFS

    LFS 家族的最后一个成员解决基于源代码的 Linux 的一个特别重要的方面:安全性。对于不想依赖于所选的 Linux 发行版服务器交付的补丁的那些人,安全性的普通方法是,针对所选的核心库和应用程序跟踪安全报告。对于 LFS 实现人员来说,问题有些不同:尽管不是不可能,但是也难以审计 Linux 内核代码,也许还包括集中于基于 Linux 的操作系统的内部机能的很多库和实用工具。

    代码审计相当费时,并且只有当补丁服务器是由专门人员集中维护的时,添加大量补丁才是明智的。但是可以取代一些为反映安全问题的新方法而重新编写过的库。一个好的例子是,通过从一个适当大的随机数池中随机分配数字,使得猜测进程标识符极为困难。OpenBSD 项目最先采用了该方法,随后,各种 UNIX 风格和 Linux 发行版都采用了该方法。

    一个相当新的项目叫做 Hardened Linux From Scratch (HLFS),在 Linux 下采用了这一安全方法。该项目假设相当正规地掌握了 LFS 和 BLFS 的一些部件,并使用了不会成为大多数 Linux 系统中的标准的几个实用工具和库。

    添加到 HLFS 中的最重要的部件可能是 Stack-Smashing Protector (SSP),通过使用 gcc 指令可以启用该功能。SSP 开发来防御 stack-smashing 攻击,这类攻击属于影响 Linux 系统的一类最常见的安全威胁。其他安全措施包括一流的随机数生成器和位置独立的可执行程序的编译,其中通常转化成静态链接对象代码的可执行代码作为共享库出现,而位置独立的可执行库通过将地址随机化可以隐藏这些地址。当然,可从 HLFS Web 站点得到大量补丁,并可查看其源代码。

    日益壮大的 LFS 家族

    在许多方面,Linux 版本的 LFS 家族是一个方法,给予黑客以构造基于 Linux 的操作系统的能力。但是对于 LFS 的创建者们来说,最重要的结果似乎是:通过 LFS,所有 Linux 发行版对于所涉及的用户都成了智能的了。通过允许用户一部分一部分地构建 Linux 发行版,并帮助用户将一个基于 Linux 的操作系统看作一个由许多部件组成的系统,还可以用另外的方法构建 Linux 发行版。

    更一般来说,用户要更改构建 Linux 发行版的方式,不必要是程序员:只要从构建 LFS 系统学到的一点脚本编写能力就足够了。LFS 专家可以改变和扩展 Linux 发行版的完美组合,而不会影响它的基本结构。对于有人员和专家维护 Linux 系统,但没有资金从咨询机构和公司购买商业支持的机构来说,该功能特别重要。已经针对教学目的和大型网络,演示了基于 LFS 的 Linux 系统。它们也有可能用于其他领域。


    21
    十一 07

    避免掉线而使任务中断的技巧

    使用环境:UNIX平台 (Linux)

    使用screen:
      在执行可能会花费时间较长的任务时,可能我们要中断网络连接而去干别的事儿,或者网络环境不太好的地方,网络会意外中断,使用screen命令,可以使网络、终端意外断开时,可重新连接至screen程序。

    其中,Ctrl+a ,0/1/2 切换screen窗口
    Ctrl+a,d 分离screen窗口
    screent -list  查看当前用户的screen窗口有哪些
    BBC-FILER-02 01:19:48 ~ # screen -list
    There is a screen on:
            17486.pts-0.BBC-FILER-02        (Detached)
    1 Socket in /tmp/screens/S-root.

    重新连接至已经存在的窗口:screen -r
    若有多个窗口,需要指点pid,screen -r 17486

    有时screen意外断线时状态为:attached
    这时无法重新连接到screen窗口,可以使用screen -D 命令分离之,然后再使用-r参数连接。


    20
    十一 07

    CentOS 4.5 上安装、使用xfs文件系统

    1. 编辑/etc/yum.repos.d/CentOS-Base.repo
      找到[centosplus],将原来的enabled=0改为enabled=1
    2. xfs相关包
      xfsprogs
      kmod-xfs-?我的内核是2.6.9-55.0.12.plus.c4smpyum install xfsprogs
      yum install kmod-xfs-smp

    18
    十一 07

    Apache URL重定向指南

    Apache URL重定向指南

    mod_rewrite入门
    Apache mod_rewrite模块是一个处理URL而又极为复杂的模块,使用mod_rewrite你可处理所有和URL有关的问题,你所付出的就是花时间去了解mod_rewrite的复杂架构,一般初学者都很难实时理解mod_rewrite的用法,有时Apache专家也要mod_rewrite来发展Apache的新功能。

    换句话说,当你成功使用mod_rewrite做到你期望的东西,就不要试图再接触mod_rewrite了,因为mod_rewrite的功能实在过于强大。本章的例子会介绍几个成功的例子给你摸索,不像FAQ形式般把你的问题解答。

    实用解决方法
    这里还有很多未被发掘的解决方法,请大家耐心地学习如何使用mod_rewrite。

    注意: 由于各人的服务器的配置都有所不同,你可能要更改设定来测试以下例子,例如使用mod_alias和mod_userdir时要加上[PT],或者使用.htaccess来重定向而非主设定文件等,请尽量理解各例子如何运作,不要生吞活剥地背诵。
     

    URL规划
    正规URL
    描述:

    在某些网页服务器中,一项资源可能会有数个URL,通常都会公布一正规URL(即真正发放的URL),其它URL都会被视为快捷方式或只供内部使用等,无论用户在使用快捷方式或正规URL,用户最后所重定向到的URL必需为正规。

    方法:

    我们可将所有非正规的URL重定向至正规的URL中,以下例子把非正规的「/~user」换成正规的「/u/user」,并且加上「/」号结尾。.

    RewriteRule   ^/~([^/]+)/?(.*)    /u/$1/$2  [R]
    RewriteRule   ^/([uge])/([^/]+)$  /$1/$2/   [R]
     

    正规主机名称
    描述:

    (省略)

    方法:

    RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
    RewriteCond %{HTTP_HOST}   !^$
    RewriteCond %{SERVER_PORT} !^80$
    RewriteRule ^/(.*)         http://fully.qualified.domain.name:%{SERVER_PORT}/$1 [L,R]
    RewriteCond %{HTTP_HOST}   !^fully\.qualified\.domain\.name [NC]
    RewriteCond %{HTTP_HOST}   !^$
    RewriteRule ^/(.*)         http://fully.qualified.domain.name/$1 [L,R]
     

    DocumentRoot被移动
    描述:

    URL的「/」通常都会映像到DocumentRoot上,但DocumentRoot有时并非重始就限定在某个目录上,它可能只是一个或多个目录的对照而矣。例如我们的内联网址为/e/www/ (WWW的主目录)和/e/sww/ (内联网的主目录)等等,因为所有的网页资料都放在/e/www/目录内,我们要确定所有内嵌的图像都能正确显示。

    方法:

    我们只要把「/」重定向至「/e/www/」,用mod_rewrite来解决比用mod_alias来解决更为简洁,因为URL别名只会比较URL的前部分,但重定向因可能涉及另一台服务器而需要不同的前缀部分(前缀部分已受DocumentRoot限制),所以mod_rewrite是最好的解决方法::

    RewriteEngine on
    RewriteRule   ^/$  /e/www/  [R]
     

    结尾斜线问题
    描述:

    每个网主都曾受到结尾斜线问题的折磨,若在URL中没有结尾斜线,服务器就会认为URL无效并返回错误,因为服务器会根据/~quux/foo去寻找foo这个档案,而非显示这个目录。其实很多时候,这问题应留待用户自己加「/」去解决,但有时你也可以完成步骤。例如你做了多次URL重定向,而目的地为一个CGI程序。

    方法:

    最直观的方法就是令Apache自动加上「/」,使用外部重定向令浏览器能正确找到档案,若我们只做内部重定向,就只能正确显示目录页,在这目录页的图像文件会因相对URL的问题而找不到。例如我们请求/~quux/foo/index.html的image.gif时,重定向后会变成/~quux/image.gif。

    所以我们应使用以下方法:

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^foo$  foo/  [R]
     

    这方法也适用于.htaccess文件在各目录内设定,但这设定会覆盖原先主配置文件。

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteCond    %{REQUEST_FILENAME}  -d
    RewriteRule    ^(.+[^/])$           $1/  [R]
     

    利用均一的URL版面规划网络群组
    描述:

    所有的网页服务器都有相同的URL版面,即无论用户向哪个主机发出请求URL,用户都会接收到相同的网页,使URL独立于服务器本身。我们的目的在于如何在Apache服务器不能响应时,都能有一个常规(而又独立于服务器运作)的网页传送给用户,设立网络群组可将这网页送至远程。

    方法:

    首先,服务器需要一外部文件把网站的用户、用户组及其它资料存储,这文件的格式如下

    user1  server_of_user1
    user2  server_of_user2
    :      :
    把以上资料存入map.xxx-to-host。然后指示服务器把URL重定向,由

    /u/user/anypath
    /g/group/anypath
    /e/entity/anypath

    http://physical-host/u/user/anypath
    http://physical-host/g/group/anypath
    http://physical-host/e/entity/anypath
    当服务器接收到不正确的URL时,服务器会跟随以下指示把URL映像到特定的档案(若URL并没有相对应的记录,就会重定向至 server0 上):

    RewriteEngine on
     
    RewriteMap      user-to-host   txt:/path/to/map.user-to-host
    RewriteMap     group-to-host   txt:/path/to/map.group-to-host
    RewriteMap    entity-to-host   txt:/path/to/map.entity-to-host
     
    RewriteRule   ^/u/([^/]+)/?(.*)   http://${user-to-host:$1|server0}/u/$1/$2
    RewriteRule   ^/g/([^/]+)/?(.*)  http://${group-to-host:$1|server0}/g/$1/$2
    RewriteRule   ^/e/([^/]+)/?(.*) http://${entity-to-host:$1|server0}/e/$1/$2
     
    RewriteRule   ^/([uge])/([^/]+)/?$          /$1/$2/.www/
    RewriteRule   ^/([uge])/([^/]+)/([^.]+.+)   /$1/$2/.www/$3\
     

    把主目录移到新的网页服务器
    描述:

    有很多网主都有以下问题:在升级时把所有用户主目录由旧的服务器移到新的服务器上。

    方法:

    使用mod_rewrite可以简单地解决这问题,把所有/~user/anypathURL重定向至http://newserver/~user/anypath

    RewriteEngine on
    RewriteRule   ^/~(.+)  http://newserver/~$1  [R,L]
     

    结构化用户主目录
    描述:

    拥有大量用户的主机通常都会把用户目录规划好,将这些目录归入一个父目录中,然后再将用户的第一个字母作该用户的父目录,例如/~foo/anypath将会是/home/f/foo/.www/anypath,而/~bar/anypath就是/home/b/bar/.www/anypath。

    方法:

    按以下指令将URL直接对映到档案系统中。

    RewriteEngine on
    RewriteRule   ^/~(([a-z])[a-z0-9]+)(.*)  /home/$2/$1/.www$3
     

    重新组织档案系统
    描述:

    这是一个麻烦的例子:在不用更动现有目录结构下,使用RewriteRules来显示整个目录结构。背景:net.sw是一个装满Unix免费软件的资料夹,并以下列结构存储:

    drwxrwxr-x   2 netsw  users    512 Aug  3 18:39 Audio/
    drwxrwxr-x   2 netsw  users    512 Jul  9 14:37 Benchmark/
    drwxrwxr-x  12 netsw  users    512 Jul  9 00:34 Crypto/
    drwxrwxr-x   5 netsw  users    512 Jul  9 00:41 Database/
    drwxrwxr-x   4 netsw  users    512 Jul 30 19:25 Dicts/
    drwxrwxr-x  10 netsw  users    512 Jul  9 01:54 Graphic/
    drwxrwxr-x   5 netsw  users    512 Jul  9 01:58 Hackers/
    drwxrwxr-x   8 netsw  users    512 Jul  9 03:19 InfoSys/
    drwxrwxr-x   3 netsw  users    512 Jul  9 03:21 Math/
    drwxrwxr-x   3 netsw  users    512 Jul  9 03:24 Misc/
    drwxrwxr-x   9 netsw  users    512 Aug  1 16:33 Network/
    drwxrwxr-x   2 netsw  users    512 Jul  9 05:53 Office/
    drwxrwxr-x   7 netsw  users    512 Jul  9 09:24 SoftEng/
    drwxrwxr-x   7 netsw  users    512 Jul  9 12:17 System/
    drwxrwxr-x  12 netsw  users    512 Aug  3 20:15 Typesetting/
    drwxrwxr-x  10 netsw  users    512 Jul  9 14:08 X11/
    我们打算把这个资料夹公开,而且希望直接地显示这资料夹的目录结构,但是我们又不想更改现有目录架构来迁就,加上我们打算开放给FTP,所以不想加入任何网页或CGI程序到这个资料夹中。

    方法:

    本方法分为两部分:第一部份是编写一系列的CGI程序来显示目录结构,这例子会把CGI和刚才的资料夹放进/e/netsw/.www/:

    -rw-r–r–   1 netsw  users    1318 Aug  1 18:10 .wwwacl
    drwxr-xr-x  18 netsw  users     512 Aug  5 15:51 DATA/
    -rw-rw-rw-   1 netsw  users  372982 Aug  5 16:35 LOGFILE
    -rw-r–r–   1 netsw  users     659 Aug  4 09:27 TODO
    -rw-r–r–   1 netsw  users    5697 Aug  1 18:01 netsw-about.html
    -rwxr-xr-x   1 netsw  users     579 Aug  2 10:33 netsw-access.pl
    -rwxr-xr-x   1 netsw  users    1532 Aug  1 17:35 netsw-changes.cgi
    -rwxr-xr-x   1 netsw  users    2866 Aug  5 14:49 netsw-home.cgi
    drwxr-xr-x   2 netsw  users     512 Jul  8 23:47 netsw-img/
    -rwxr-xr-x   1 netsw  users   24050 Aug  5 15:49 netsw-lsdir.cgi
    -rwxr-xr-x   1 netsw  users    1589 Aug  3 18:43 netsw-search.cgi
    -rwxr-xr-x   1 netsw  users    1885 Aug  1 17:41 netsw-tree.cgi
    -rw-r–r–   1 netsw  users     234 Jul 30 16:35 netsw-unlimit.lst
    DATA/子目录就是刚才的资料夹,net.sw内的软件会经rdist程序来自动更新。第二部份将这资料夹和新建立的CGI、网页配合,我们想将DATA/稳藏起来,而在用户请求不同URL时执行正确的CGI程序来显示。先将/net.sw/这URL重定向至/e/netsw:

    RewriteRule  ^net.sw$       net.sw/        [R]
    RewriteRule  ^net.sw/(.*)$  e/netsw/$1
     

    第一条规则纯粹补加URL结尾的「/」号,而第二条规则就是把URL重定向。之后将下列配置存入/e/netsw/.www/.wwwacl:

    Options       ExecCGI FollowSymLinks Includes MultiViews
     
    RewriteEngine on
     
    #  we are reached via /net.sw/ prefix
    RewriteBase   /net.sw/
     
    #  first we rewrite the root dir to
    #  the handling cgi script
    RewriteRule   ^$                       netsw-home.cgi     [L]
    RewriteRule   ^index\.html$            netsw-home.cgi     [L]
     
    #  strip out the subdirs when
    #  the browser requests us from perdir pages
    RewriteRule   ^.+/(netsw-[^/]+/.+)$    $1                 [L]
     
    #  and now break the rewriting for local files
    RewriteRule   ^netsw-home\.cgi.*       -                  [L]
    RewriteRule   ^netsw-changes\.cgi.*    -                  [L]
    RewriteRule   ^netsw-search\.cgi.*     -                  [L]
    RewriteRule   ^netsw-tree\.cgi$        -                  [L]
    RewriteRule   ^netsw-about\.html$      -                  [L]
    RewriteRule   ^netsw-img/.*$           -                  [L]
     
    #  anything else is a subdir which gets handled
    #  by another cgi script
    RewriteRule   !^netsw-lsdir\.cgi.*     -                  [C]
    RewriteRule   (.*)                     netsw-lsdir.cgi/$1
     

    提示:

    1.        留意第四部份的L(last)旗标及代表不用更改的(‘-’)符号

    2.        留意最后部份第一条规则的 ! (not)字符,及 C (chain) 链接符

    3.        留意最后一条规则代表全部更新的语法

    以Apache的mod_imap取代NCSA的imagemap
    描述:

    很多人都想顺利地把旧的NCSA服务器迁至新的Apache服务器,所以我们都想将旧的NCSA imagemap顺利转换到Apache的mod_imap,问题是imagemap已被很多超级链接连系着,但旧的imagemap是存储在/cgi-bin/imagemap/path/to/page.map,而在Apache却是放在/path/to/page.map。

    方法:

    我们只要将「/cgi-bin/」移除便可:

    RewriteEngine  on
    RewriteRule    ^/cgi-bin/imagemap(.*)  $1  [PT]
     

    在多个目录下搜寻网页
    描述:

    MultiViews亦不能指示Apache在多个目录里搜寻网页。

    方法:

    请参看以下指令。

    RewriteEngine on
     
    #   first try to find it in custom/…
    #   …and if found stop and be happy:
    RewriteCond         /your/docroot/dir1/%{REQUEST_FILENAME}  -f
    RewriteRule  ^(.+)  /your/docroot/dir1/$1  [L]
     
    #   second try to find it in pub/…
    #   …and if found stop and be happy:
    RewriteCond         /your/docroot/dir2/%{REQUEST_FILENAME}  -f
    RewriteRule  ^(.+)  /your/docroot/dir2/$1  [L]
     
    #   else go on for other Alias or ScriptAlias directives,
    #   etc.
    RewriteRule   ^(.+)  -  [PT]
     

    跟据URL设定环境变量
    描述:

    在页面间传递讯息可以用CGI程序完成,但你却不想用CGI而用URL来传递。

    方法:

    以下指令将变量及其值抽出URL外,然后记入自设的环境变量中,该变量可由XSSI或CGI存取。例如把/foo/S=java/bar/转换为/foo/bar/,然后把「java」写入环境变量「STATUS」。

    RewriteEngine on
    RewriteRule   ^(.*)/S=([^/]+)/(.*)    $1/$3 [E=STATUS:$2]
     

    虚拟用户主机
    描述:

    你只想根据DNS记录将www.username.host.domain.com的请求直接对映到档案系统,放弃使用Apache的虚拟主机功能。

    方法:

    只有HTTP/1.1请求才可用以下方法做到,我们可根据HTTP Header把http://www.username.host.com/anypath重定向到/home/username/anypath:

    RewriteEngine on
    RewriteCond   %{HTTP_HOST}                 ^www\.[^.]+\.host\.com$
    RewriteRule   ^(.+)                        %{HTTP_HOST}$1          [C]
    RewriteRule   ^www\.([^.]+)\.host\.com(.*) /home/$1$2
     

    将远程请求重定向至另一个用户主目录
    描述:

    当用者的主机不属于自己的网域ourdomain.com时,就将请求重定向至www.somewhere.com</CODE。< dd>

    方法:

    请参看以下指令:

    RewriteEngine on
    RewriteCond   %{REMOTE_HOST}  !^.+\.ourdomain\.com$
    RewriteRule   ^(/~.+)         http://www.somewhere.com/$1 [R,L]
     

    将失败的网页请求重定向至另一部网页服务器
    描述:

    这是一般常见的疑问,最直观的方法就是用ErrorDocument加上CGI-scripts更改目标URL,但我们亦可使用mod_rewrite来实行(这方法的效率却比CGI程序更低)。

    方法:

    再一次留意CGI会是更有效率的解决方法,而mod_rewrite的好处在于更安全及易设置:

    RewriteEngine on
    RewriteCond   /your/docroot/%{REQUEST_FILENAME} !-f
    RewriteRule   ^(.+)                             http://webserverB.dom/$1
     

    以上例子会限制所有网页在DocumentRoot才能成功,我们可加多一点指令来改善:

    RewriteEngine on
    RewriteCond   %{REQUEST_URI} !-U
    RewriteRule   ^(.+)          http://webserverB.dom/$1
     

    这例子使用了mod_rewrite预计URL改动的功能,所有URL都可以安全地重定向至新的目录,但在速度慢的主机上不宜使用这方法,因为采用本例会拖慢服务器工作,当然你可以在高速CPU主机上使用。

    更广泛的URL重定向
    描述:

    我们想重定向有控制字符的URL,例如”url#anchor”等,通常Apache会用uri_escape()函数来隔除这些控制字符,因此你不可以直接用mod_rewrite来重定向这类URL。

    方法:

    我们要使用一NPH-CGI(NPH = non-parseable headers)程序处理重定向工作,因为NPH-CGI不会隔除控制字符。首先,我们先利用xredirect:

    RewriteRule ^xredirect:(.+) /path/to/nph-xredirect.cgi/$1 \
                [T=application/x-httpd-cgi,L]
     

    强制性将所有URL加上xredirect,然后将URL导入nph-xredirect.cgi中,程序代码如下:

    #!/path/to/perl
    ##
    ##  nph-xredirect.cgi — NPH/CGI script for extended redirects
    ##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
    ##
     
    $| = 1;
    $url = $ENV{‘PATH_INFO’};
     
    print “HTTP/1.0 302 Moved Temporarily\n”;
    print “Server: $ENV{‘SERVER_SOFTWARE’}\n”;
    print “Location: $url\n”;
    print “Content-type: text/html\n”;
    print “\n”;
    print “<html>\n”;
    print “<head>\n”;
    print “<title>302 Moved Temporarily (EXTENDED)</title>\n”;
    print “</head>\n”;
    print “<body>\n”;
    print “<h1>Moved Temporarily (EXTENDED)</h1>\n”;
    print “The document has moved <a HREF=\”$url\”>here</a>.<p>\n”;
    print “</body>\n”;
    print “</html>\n”;
     
    ##EOF##
     

    这样可将所有能或不能直接用mod_rewrite来重定向的URL,经CGI来完成了。例如你可将某URL重定向至新闻服务器

    RewriteRule ^anyurl  xredirect:news:newsgroup
     

    注意:你不需在每条规则后加上[R]或[R,L]。

    多样化资料夹存取
    描述:

    若你曾浏览http://www.perl.com/CPAN (CPAN = Comprehensive Perl Archive Network),它会把你重定向至其中一个最近你主机地区的FTP服务器,事实上这应该叫多样化FTP存取。CPAN用CGI来实行这服务,这次我们用mod_rewrite。

    <STRONG方法:< strong>

    由mod_rewrite 3.0.0开始可使用「ftp:」重定向至FTP服务器,用户主机的地区可依URL的顶层域名来决定,而顶层域名及FTP服务器位置的对照就存入某档案中。

    RewriteEngine on
    RewriteMap    multiplex                txt:/path/to/map.cxan
    RewriteRule   ^/CxAN/(.*)              %{REMOTE_HOST}::$1                 [C]
    RewriteRule   ^.+\.([a-zA-Z]+)::(.*)$  ${multiplex:$1|ftp.default.dom}$2  [R,L]
     

    ##
    ##  map.cxan — Multiplexing Map for CxAN
    ##
     
    de        ftp://ftp.cxan.de/CxAN/
    uk        ftp://ftp.cxan.uk/CxAN/
    com       ftp://ftp.cxan.com/CxAN/
     :
    ##EOF##
     

    在某段时间执行不同的重定向
    描述n:

    很多网主仍用CGI随着不同时间将URL重定向至不同的网页。

    方法:

    mod_rewrite设有很多以TIME_xxx开始的环境变量,将这些时间环境变量进行字符串比较可决定重定向至哪个网页:

    RewriteEngine on
    RewriteCond   %{TIME_HOUR}%{TIME_MIN} >0700
    RewriteCond   %{TIME_HOUR}%{TIME_MIN} <1900
    RewriteRule   ^foo\.html$             foo.day.html
    RewriteRule   ^foo\.html$             foo.night.html
     

    在07:00-19:00就显示foo.day.html,其余时间则显示foo.html

    保留旧有文件的URL
    描述:

    更改文件的扩展名后,如何让旧的URL能对映到这新的文件。

    方法:

    把旧的URL用mod_rewrite重定向至新的文件,若有正确的新文件就对映到这文件,没有的话便对映到原有文件。

    #   backward compatibility ruleset for
    #   rewriting document.html to document.phtml
    #   when and only when document.phtml exists
    #   but no longer document.html
    RewriteEngine on
    RewriteBase   /~quux/
    #   parse out basename, but remember the fact
    RewriteRule   ^(.*)\.html$              $1      [C,E=WasHTML:yes]
    #   rewrite to document.phtml if exists
    RewriteCond   %{REQUEST_FILENAME}.phtml -f
    RewriteRule   ^(.*)$ $1.phtml                   [S=1]
    #   else reverse the previous basename cutout
    RewriteCond   %{ENV:WasHTML}            ^yes$
    RewriteRule   ^(.*)$ $1.html
     

    内容控制
    由旧的档名转到新的文件名 (档案系统)
    描述:

    假设我们将bar.html改名为foo.html,而我们又想保留旧有的URL,甚至不想给用户新的URL去连至这新档案。

    方法:

    将旧的档案对映到新的档案:

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^foo\.html$  bar.html
     

    由旧的档名转到新的档名 (URL)
    描述:

    和刚才的例子一样,我们把bar.html改名为foo.html,但这次我们想直接将用户的网页重定向至新的文件,即浏览器的URL位置有所改变。

    方法:

    强制性将URL对映到新的URL:

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^foo\.html$  bar.html  [R]
     

    由浏览器种类控制内容
    描述:

    一个出色的网页应能支持各种浏览器,例如我们要把完整版网页传送至Netscape,但就要传送文字版至Lynx。

    方法:

    由于浏览器没有提供Apache格式的浏览器种类资料,所以我们不可使用内文转换(mod_negotiation),我们必需用「User-Agent」决定浏览器种类。例如User-Agent为「Mozilla/3」就把「foo.html」重定向至「foo.NS.html」;若浏览器为「Lynx」或「Mozilla」就重定向至foo.20.html,其它种类的浏览器则导向至foo.32.html:

    RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/3.*
    RewriteRule ^foo\.html$         foo.NS.html          [L]
     
    RewriteCond %{HTTP_USER_AGENT}  ^Lynx/.*         [OR]
    RewriteCond %{HTTP_USER_AGENT}  ^Mozilla/[12].*
    RewriteRule ^foo\.html$         foo.20.html          [L]
     
    RewriteRule ^foo\.html$         foo.32.html          [L]
     

    动态本地档案更新(经镜像网站)
    描述:

    你想将某个主机的网页连结到你的网页目录,若被连结的是FTP服务器,你可用mirror程序将最新的档案移到自己的主机上,我们可用webcopy经网页服务器HTTP把档案下载,但这方法有一坏处:只有在执行webcopy时才能更新档案。更好的办法就是在发出请求时立刻找寻最新的档案来源,然后实时下载到自己主机中。

    方法:

    利用Proxy Throughput(flag [P])把远程网页甚至整个网站建立一直接对照。

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^hotsheet/(.*)$  http://www.tstimpreso.com/hotsheet/$1  [P]
     

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^usa-news\.html$   http://www.quux-corp.com/news/index.html  [P]
     

    动态镜像档案更新(经本主机)
    描述:

    (省略)

    方法:

    RewriteEngine on
    RewriteCond   /mirror/of/remotesite/$1           -U
    RewriteRule   ^http://www\.remotesite\.com/(.*)$ /mirror/of/remotesite/$1
     

    由内部网络更新档案
    描述:

    为了安全起见,我们建立了两个网页服务器,第一个是公开的(www.quux-corp.dom),第二个则是内部使用,受防火墙所保护,一切资料及网站维护都经这个服务器进行,现在我们想令外部服务器能存取穿过防火墙,获取内部服务器已最新的档案。

    方法:

    我们只容许外部服务器从内部获取资料,一切直接获取的请求都受防火墙拒绝,先在防火墙设定:

    ALLOW Host www.quux-corp.dom Port >1024 –> Host www2.quux-corp.dom Port 80 
    DENY  Host *                 Port *     –> Host www2.quux-corp.dom Port 80
     

    把以上的字句译成设置防火墙的语法,然后在mod_rewrite透过proxy throughput获取最新资料:

    RewriteRule ^/~([^/]+)/?(.*)          /home/$1/.www/$2
    RewriteCond %{REQUEST_FILENAME}       !-f
    RewriteCond %{REQUEST_FILENAME}       !-d
    RewriteRule ^/home/([^/]+)/.www/?(.*) http://www2.quux-corp.dom/~$1/pub/$2 [P]
     

    平衡服务器负荷
    描述:

    我们想将www[0-5].foo.com这六部服务器的工作量平均分配。

    方法:

    当然你会有很多方法达成,一般都会使用DNS,介绍完DNS后再会讨论mod_rewrite如何实行。

    1.     DNS循环机制

    最简单的方法就是使用BIND的循环机制,e.g.

    www0   IN  A       1.2.3.1
    www1   IN  A       1.2.3.2
    www2   IN  A       1.2.3.3
    www3   IN  A       1.2.3.4
    www4   IN  A       1.2.3.5
    www5   IN  A       1.2.3.6
     

    然后加上以下记录:

    www    IN  CNAME   www0.foo.com.
           IN  CNAME   www1.foo.com.
           IN  CNAME   www2.foo.com.
           IN  CNAME   www3.foo.com.
           IN  CNAME   www4.foo.com.
           IN  CNAME   www5.foo.com.
           IN  CNAME   www6.foo.com.
     

    在DNS层面上这种设定当然是错的,但我们正好使用了BIND的循环机制,BIND接收到www.foo.com的解析请求,然后BIND就会循环地解析作www0-www6,这样就能将用户分配到不同的服务器上,但请记得这不是一个完美的方案,因为其它的域名服务器会快取你服务器的域名解析结果,所以每一次解析到wwwX.foo.com时,都会有很多用户同时被派往同一部服务器,但整体来说已能平衡各服务器的负荷。

    2.     DNS平衡负荷

    http://www.stanford.edu/~schemers/docs/lbnamed/lbnamed.html有一个lbnamed程序专责利用域名服务器把用户请求分发到不同的服务器上,这是一个用Perl 5及其它附助工具写的复杂DNS工作量分配程序。

    3.     代理服务器循环建立机制

    我们使用mod_rewrite及其代理服务器网页记录(proxy throughput)功能,先在DNS加入www0.foo.com即是www.foo.com的记录。

    www    IN  CNAME   www0.foo.com.
     

    然后将www0.foo.com变为一独立代理服务器,即是建立一专责代理服务器,然后把请求分流至五部不同的服务器(www1-www5),我们用lb.pl及以下mod_rewrite规则:

    RewriteEngine on
    RewriteMap    lb      prg:/path/to/lb.pl
    RewriteRule   ^/(.+)$ ${lb:$1}           [P,L]
     

    lb.pl的程序代码:

    #!/path/to/perl
    ##
    ##  lb.pl — load balancing script
    ##
     
    $| = 1;
     
    $name   = “www”;     # the hostname base
    $first  = 1;         # the first server (not 0 here, because 0 is myself)
    $last   = 5;         # the last server in the round-robin
    $domain = “foo.dom”; # the domainname
     
    $cnt = 0;
    while (<STDIN>) {
        $cnt = (($cnt+1) % ($last+1-$first));
        $server = sprintf(“%s%d.%s”, $name, $cnt+$first, $domain);
        print “http://$server/$_”;
    }
     
    ##EOF##
     

    注意,www0.foo.com这服务器的工作量仍然和以前一样高,但这服务器的工作就只是负责分流,所有SSI、CGI、ePerl请求都由其它服务器执行,所以整体的工作量已经减少了许多。

    4.     硬件/TCP循环机制

    可Cisco的LocalDirector在TCP/IP网络层上把用户请求分流,事实上这种分流程序已刻烙在是电路板上。与硬件有关的解决方法通常都需要大量的金钱,但执行效率就会是最高。

    将请求重定向至代理服务器
    描述:

    (省略)

    方法:

    ##
    ##  apache-rproxy.conf — Apache configuration for Reverse Proxy Usage
    ##
     
    #   server type
    ServerType           standalone
    Port                 8000
    MinSpareServers      16
    StartServers         16
    MaxSpareServers      16
    MaxClients           16
    MaxRequestsPerChild  100
     
    #   server operation parameters
    KeepAlive            on
    MaxKeepAliveRequests 100
    KeepAliveTimeout     15
    Timeout              400
    IdentityCheck        off
    HostnameLookups      off
     
    #   paths to runtime files
    PidFile              /path/to/apache-rproxy.pid
    LockFile             /path/to/apache-rproxy.lock
    ErrorLog             /path/to/apache-rproxy.elog
    CustomLog            /path/to/apache-rproxy.dlog “%{%v/%T}t %h -> %{SERVER}e URL: %U”
     
    #   unused paths
    ServerRoot           /tmp
    DocumentRoot         /tmp
    CacheRoot            /tmp
    RewriteLog           /dev/null
    TransferLog          /dev/null
    TypesConfig          /dev/null
    AccessConfig         /dev/null
    ResourceConfig       /dev/null
     
    #   speed up and secure processing
    <Directory />
    Options -FollowSymLinks -SymLinksIfOwnerMatch
    AllowOverride None
    </Directory>
     
    #   the status page for monitoring the reverse proxy
    <Location /apache-rproxy-status>
    SetHandler server-status
    </Location>
     
    #   enable the URL rewriting engine
    RewriteEngine        on
    RewriteLogLevel      0
     
    #   define a rewriting map with value-lists where
    #   mod_rewrite randomly chooses a particular value
    RewriteMap     server  rnd:/path/to/apache-rproxy.conf-servers
     
    #   make sure the status page is handled locally
    #   and make sure no one uses our proxy except ourself
    RewriteRule    ^/apache-rproxy-status.*  -  [L]
    RewriteRule    ^(http|ftp)://.*          -  [F]
     
    #   now choose the possible servers for particular URL types
    RewriteRule    ^/(.*\.(cgi|shtml))$  to://${server:dynamic}/$1  [S=1]
    RewriteRule    ^/(.*)$               to://${server:static}/$1 
     
    #   and delegate the generated URL by passing it
    #   through the proxy module
    RewriteRule    ^to://([^/]+)/(.*)    http://$1/$2   [E=SERVER:$1,P,L]
     
    #   and make really sure all other stuff is forbidden
    #   when it should survive the above rules…
    RewriteRule    .*                    -              [F]
     
    #   enable the Proxy module without caching
    ProxyRequests        on
    NoCache              *
     
    #   setup URL reverse mapping for redirect reponses
    ProxyPassReverse  /  http://www1.foo.dom/
    ProxyPassReverse  /  http://www2.foo.dom/
    ProxyPassReverse  /  http://www3.foo.dom/
    ProxyPassReverse  /  http://www4.foo.dom/
    ProxyPassReverse  /  http://www5.foo.dom/
    ProxyPassReverse  /  http://www6.foo.dom/
     

    ##
    ##  apache-rproxy.conf-servers — Apache/mod_rewrite selection table
    ##
     
    #   list of backend servers which serve static
    #   pages (HTML files and Images, etc.)
    static    www1.foo.dom|www2.foo.dom|www3.foo.dom|www4.foo.dom
     
    #   list of backend servers which serve dynamically
    #   generated page (CGI programs or mod_perl scripts)
    dynamic   www5.foo.dom|www6.foo.dom
     

    建立新的档案型态及服务
    描述:

    你可在网上找到大量华丽的CGI程序,但又因这些CGI的艰难用法,很多人都不愿意使用,甚至Apache Action Handler的MIME类型亦On the net there are a lot of nifty CGI programs. But their usage is usually boring, so a lot of webmaster don’t use them. Even Apache’s Action handler feature for MIME-types is only appropriate when the CGI programs don’t need special URLs (actually PATH_INFO and QUERY_STRINGS) as their input. First, let us configure a new file type with extension .scgi (for secure CGI) which will be processed by the popular cgiwrap program. The problem here is that for instance we use a Homogeneous URL Layout (see above) a file inside the user homedirs has the URL /u/user/foo/bar.scgi. But cgiwrap needs the URL in the form /~user/foo/bar.scgi/. The following rule solves the problem:

    RewriteRule ^/[uge]/([^/]+)/\.www/(.+)\.scgi(.*) …
    … /internal/cgi/user/cgiwrap/~$1/$2.scgi$3  [NS,T=application/x-http-cgi]
     

    Or assume we have some more nifty programs: wwwlog (which displays the access.log for a URL subtree and wwwidx (which runs Glimpse on a URL subtree). We have to provide the URL area to these programs so they know on which area they have to act on. But usually this ugly, because they are all the times still requested from that areas, i.e. typically we would run the swwidx program from within /u/user/foo/ via hyperlink to

    /internal/cgi/user/swwidx?i=/u/user/foo/
    which is ugly. Because we have to hard-code both the location of the area and the location of the CGI inside the hyperlink. When we have to reorganise or area, we spend a lot of time changing the various hyperlinks.

    Solution:

    The solution here is to provide a special new URL format which automatically leads to the proper CGI invocation. We configure the following:

    RewriteRule   ^/([uge])/([^/]+)(/?.*)/\*  /internal/cgi/user/wwwidx?i=/$1/$2$3/
    RewriteRule   ^/([uge])/([^/]+)(/?.*):log /internal/cgi/user/wwwlog?f=/$1/$2$3
     

    Now the hyperlink to search at /u/user/foo/ reads only

    HREF=”*”
    which internally gets automatically transformed to

    /internal/cgi/user/wwwidx?i=/u/user/foo/
    The same approach leads to an invocation for the access log CGI program when the hyperlink :log gets used.

    From Static to Dynamic
    Description:

    How can we transform a static page foo.html into a dynamic variant foo.cgi in a seemless way, i.e. without notice by the browser/user.

    Solution:

    We just rewrite the URL to the CGI-script and force the correct MIME-type so it gets really run as a CGI-script. This way a request to /~quux/foo.html internally leads to the invokation of /~quux/foo.cgi.

    RewriteEngine  on
    RewriteBase    /~quux/
    RewriteRule    ^foo\.html$  foo.cgi  [T=application/x-httpd-cgi]
     

    On-the-fly Content-Regeneration
    Description:

    Here comes a really esoteric feature: Dynamically generated but statically served pages, i.e. pages should be delivered as pure static pages (read from the filesystem and just passed through), but they have to be generated dynamically by the webserver if missing. This way you can have CGI-generated pages which are statically served unless one (or a cronjob) removes the static contents. Then the contents gets refreshed.

    Solution:

    This is done via the following ruleset:

    RewriteCond %{REQUEST_FILENAME}   !-s
    RewriteRule ^page\.html$          page.cgi   [T=application/x-httpd-cgi,L]
     

    Here a request to page.html leads to a internal run of a corresponding page.cgi if page.html is still missing or has filesize null. The trick here is that page.cgi is a usual CGI script which (additionally to its STDOUT) writes its output to the file page.html. Once it was run, the server sends out the data of page.html. When the webmaster wants to force a refresh the contents, he just removes page.html (usually done by a cronjob).

    Document With Autorefresh
    Description:

    Wouldn’t it be nice while creating a complex webpage if the webbrowser would automatically refresh the page every time we write a new version from within our editor? Impossible?

    Solution:

    No! We just combine the MIME multipart feature, the webserver NPH feature and the URL manipulation power of mod_rewrite. First, we establish a new URL feature: Adding just :refresh to any URL causes this to be refreshed every time it gets updated on the filesystem.

    RewriteRule   ^(/[uge]/[^/]+/?.*):refresh  /internal/cgi/apache/nph-refresh?f=$1
     

    Now when we reference the URL

    /u/foo/bar/page.html:refresh
    this leads to the internal invocation of the URL

    /internal/cgi/apache/nph-refresh?f=/u/foo/bar/page.html
    The only missing part is the NPH-CGI script. Although one would usually say “left as an exercise to the reader” ;-) I will provide this, too.

    #!/sw/bin/perl
    ##
    ##  nph-refresh — NPH/CGI script for auto refreshing pages
    ##  Copyright (c) 1997 Ralf S. Engelschall, All Rights Reserved.
    ##
    $| = 1;
     
    #   split the QUERY_STRING variable
    @pairs = split(/&/, $ENV{‘QUERY_STRING’});
    foreach $pair (@pairs) {
        ($name, $value) = split(/=/, $pair);
        $name =~ tr/A-Z/a-z/;
        $name = ‘QS_’. $name;
        $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack(“C”, hex($1))/eg;
        eval “\$$name = \”$value\”";
    }
    $QS_s = 1 if ($QS_s eq ”);
    $QS_n = 3600 if ($QS_n eq ”);
    if ($QS_f eq ”) {
        print “HTTP/1.0 200 OK\n”;
        print “Content-type: text/html\n\n”;
        print “&lt;b&gt;ERROR&lt;/b&gt;: No file given\n”;
        exit(0);
    }
    if (! -f $QS_f) {
        print “HTTP/1.0 200 OK\n”;
        print “Content-type: text/html\n\n”;
        print “&lt;b&gt;ERROR&lt;/b&gt;: File $QS_f not found\n”;
        exit(0);
    }
     
    sub print_http_headers_multipart_begin {
        print “HTTP/1.0 200 OK\n”;
        $bound = “ThisRandomString12345″;
        print “Content-type: multipart/x-mixed-replace;boundary=$bound\n”;
        &print_http_headers_multipart_next;
    }
     
    sub print_http_headers_multipart_next {
        print “\n–$bound\n”;
    }
     
    sub print_http_headers_multipart_end {
        print “\n–$bound–\n”;
    }
     
    sub displayhtml {
        local($buffer) = @_;
        $len = length($buffer);
        print “Content-type: text/html\n”;
        print “Content-length: $len\n\n”;
        print $buffer;
    }
     
    sub readfile {
        local($file) = @_;
        local(*FP, $size, $buffer, $bytes);
        ($x, $x, $x, $x, $x, $x, $x, $size) = stat($file);
        $size = sprintf(“%d”, $size);
        open(FP, “&lt;$file”);
        $bytes = sysread(FP, $buffer, $size);
        close(FP);
        return $buffer;
    }
     
    $buffer = &readfile($QS_f);
    &print_http_headers_multipart_begin;
    &displayhtml($buffer);
     
    sub mystat {
        local($file) = $_[0];
        local($time);
     
        ($x, $x, $x, $x, $x, $x, $x, $x, $x, $mtime) = stat($file);
        return $mtime;
    }
     
    $mtimeL = &mystat($QS_f);
    $mtime = $mtime;
    for ($n = 0; $n &lt; $QS_n; $n++) {
        while (1) {
            $mtime = &mystat($QS_f);
            if ($mtime ne $mtimeL) {
                $mtimeL = $mtime;
                sleep(2);
                $buffer = &readfile($QS_f);
                &print_http_headers_multipart_next;
                &displayhtml($buffer);
                sleep(5);
                $mtimeL = &mystat($QS_f);
                last;
            }
            sleep($QS_s);
        }
    }
     
    &print_http_headers_multipart_end;
     
    exit(0);
     
    ##EOF##
    Mass Virtual Hosting
    Description:

    The <VirtualHost> feature of Apache is nice and works great when you just have a few dozens virtual hosts. But when you are an ISP and have hundreds of virtual hosts to provide this feature is not the best choice.

    Solution:

    To provide this feature we map the remote webpage or even the complete remote webarea to our namespace by the use of the Proxy Throughput feature (flag [P]):

    ##
    ##  vhost.map
    ##
    www.vhost1.dom:80  /path/to/docroot/vhost1
    www.vhost2.dom:80  /path/to/docroot/vhost2
         :
    www.vhostN.dom:80  /path/to/docroot/vhostN
     

    ##
    ##  httpd.conf
    ##
        :
    #   use the canonical hostname on redirects, etc.
    UseCanonicalName on
     
        :
    #   add the virtual host in front of the CLF-format
    CustomLog  /path/to/access_log  “%{VHOST}e %h %l %u %t \”%r\” %>s %b”
        :
     
    #   enable the rewriting engine in the main server
    RewriteEngine on
     
    #   define two maps: one for fixing the URL and one which defines
    #   the available virtual hosts with their corresponding
    #   DocumentRoot.
    RewriteMap    lowercase    int:tolower
    RewriteMap    vhost        txt:/path/to/vhost.map
     
    #   Now do the actual virtual host mapping
    #   via a huge and complicated single rule:
    #
    #   1. make sure we don’t map for common locations
    RewriteCond   %{REQUEST_URI}  !^/commonurl1/.*
    RewriteCond   %{REQUEST_URI}  !^/commonurl2/.*
        :
    RewriteCond   %{REQUEST_URI}  !^/commonurlN/.*
    #
    #   2. make sure we have a Host header, because
    #      currently our approach only supports
    #      virtual hosting through this header
    RewriteCond   %{HTTP_HOST}  !^$
    #
    #   3. lowercase the hostname
    RewriteCond   ${lowercase:%{HTTP_HOST}|NONE}  ^(.+)$
    #
    #   4. lookup this hostname in vhost.map and
    #      remember it only when it is a path
    #      (and not “NONE” from above)
    RewriteCond   ${vhost:%1}  ^(/.*)$
    #
    #   5. finally we can map the URL to its docroot location
    #      and remember the virtual host for logging puposes
    RewriteRule   ^/(.*)$   %1/$1  [E=VHOST:${lowercase:%{HTTP_HOST}}]
        :
     

    Access Restriction
    Blocking of Robots
    Description:

    How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file containing entries of the “Robot Exclusion Protocol” is typically not enough to get rid of such a robot.

    Solution:

    We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory indexed area where the robot traversal would create big server load). We have to make sure that we forbid access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough. This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header information.

    RewriteCond %{HTTP_USER_AGENT}   ^NameOfBadRobot.*     
    RewriteCond %{REMOTE_ADDR}       ^123\.45\.67\.[8-9]$
    RewriteRule ^/~quux/foo/arc/.+   -   [F]
     

    Blocked Inline-Images
    Description:

    Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are nice, so others directly incorporate them via hyperlinks to their pages. We don’t like this practice because it adds useless traffic to our server.

    Solution:

    While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser sends a HTTP Referer header.

    RewriteCond %{HTTP_REFERER} !^$                                 
    RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
    RewriteRule .*\.gif$        -                                    [F]
     

    RewriteCond %{HTTP_REFERER}         !^$                                 
    RewriteCond %{HTTP_REFERER}         !.*/foo-with-gif\.html$
    RewriteRule ^inlined-in-foo\.gif$   -                        [F]
     

    Host Deny
    Description:

    How can we forbid a list of externally configured hosts from using our server?

    Solution:

    For Apache >= 1.3b6:

    RewriteEngine on
    RewriteMap    hosts-deny  txt:/path/to/hosts.deny
    RewriteCond   ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND} !=NOT-FOUND [OR]
    RewriteCond   ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND} !=NOT-FOUND
    RewriteRule   ^/.*  -  [F]
     

    For Apache <= 1.3b6:

    RewriteEngine on
    RewriteMap    hosts-deny  txt:/path/to/hosts.deny
    RewriteRule   ^/(.*)$ ${hosts-deny:%{REMOTE_HOST}|NOT-FOUND}/$1
    RewriteRule   !^NOT-FOUND/.* – [F]
    RewriteRule   ^NOT-FOUND/(.*)$ ${hosts-deny:%{REMOTE_ADDR}|NOT-FOUND}/$1
    RewriteRule   !^NOT-FOUND/.* – [F]
    RewriteRule   ^NOT-FOUND/(.*)$ /$1
     

    ##
    ##  hosts.deny
    ##
    ##  ATTENTION! This is a map, not a list, even when we treat it as such.
    ##             mod_rewrite parses it for key/value pairs, so at least a
    ##             dummy value “-” must be present for each entry.
    ##
     
    193.102.180.41 -
    bsdti1.sdm.de  -
    192.76.162.40  -
     

    URL-Restricted Proxy
    Description:

    How can we restrict the proxy to allow access to a configurable set of internet sites only? The site list is extracted from a prepared bookmarks file.

    Solution:

    We first have to make sure mod_rewrite is below(!) mod_proxy in the Configuration file when compiling the Apache webserver (or in the AddModule list of httpd.conf in the case of dynamically loaded modules), as it must get called _before_ mod_proxy.

    For simplicity, we generate the site list as a textfile map (but see the mod_rewrite documentation for a conversion script to DBM format). A typical Netscape bookmarks file can be converted to a list of sites with a shell script like this:

    #!/bin/sh
    cat ${1:-~/.netscape/bookmarks.html} |
    tr -d ‘\015′ | tr ‘[A-Z]‘ ‘[a-z]‘ | grep href=\” |
    sed -e ‘/href=”file:/d;’-e ‘/href=”news:/d;’ \
        -e ‘s|^.*href=”[^:]*://\([^:/"]*\).*$|\1 OK|;’\
        -e ‘/href=”/s|^.*href=”\([^:/"]*\).*$|\1 OK|;’|
    sort -u
     

    We redirect the resulting output into a text file called goodsites.txt. It now looks similar to this:

    www.apache.org OK
    xml.apache.org OK
    jakarta.apache.org OK
    perl.apache.org OK

     

    We reference this site file within the configuration for the VirtualHost which is responsible for serving as a proxy (often not port 80, but 81, 8080 or 8008).

    <VirtualHost *:8008>
      …
      RewriteEngine   On
      # Either use the (plaintext) allow list from goodsites.txt
      RewriteMap      ProxyAllow   txt:/usr/local/apache/conf/goodsites.txt
      # Or, for faster access, convert it to a DBM database:
      #RewriteMap     ProxyAllow   dbm:/usr/local/apache/conf/goodsites
      # Match lowercased hostnames
      RewriteMap      lowercase    int:tolower
      # Here we go:
      # 1) first lowercase the site name and strip off a :port suffix
      RewriteCond  ${lowercase:%{HTTP_HOST}}    ^([^:]*).*$
      # 2) next look it up in the map file.
      #    “%1″ refers to the previous regex.
      #    If the result is “OK”, proxy access is granted.
      RewriteCond  ${ProxyAllow:%1|DENY}        !^OK$          [NC]
      # 3) Disallow proxy requests if the site was _not_ tagged “OK”:
      RewriteRule  ^proxy:                      -              [F]
      …
    </VirtualHost>
     

    Proxy Deny
    Description:

    How can we forbid a certain host or even a user of a special host from using the Apache proxy?

    Solution:

    We first have to make sure mod_rewrite is below(!) mod_proxy in the Configuration file when compiling the Apache webserver. This way it gets called _before_ mod_proxy. Then we configure the following for a host-dependend deny…

    RewriteCond %{REMOTE_HOST} ^badhost\.mydomain\.com$
    RewriteRule !^http://[^/.]\.mydomain.com.*  – [F]
     

    …and this one for a user@host-dependend deny:

    RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST^badguy@badhost\.mydomain\.com$
    RewriteRule !^http://[^/.]\.mydomain.com.*  – [F]
     

    Special Authentication Variant
    Description:

    Sometimes a very special authentication is needed, for instance a authentication which checks for a set of explicitly configured users. Only these should receive access and without explicit prompting (which would occur when using the Basic Auth via mod_access).

    Solution:

    We use a list of rewrite conditions to exclude all except our friends:

    RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend1@client1.quux-corp\.com$
    RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend2@client2.quux-corp\.com$
    RewriteCond %{REMOTE_IDENT}@%{REMOTE_HOST} !^friend3@client3.quux-corp\.com$
    RewriteRule ^/~quux/only-for-friends/      -                                 [F]
     

    Referer-based Deflector
    Description:

    How can we program a flexible URL Deflector which acts on the “Referer” HTTP header and can be configured with as many referring pages as we like?

    Solution:

    Use the following really tricky ruleset…

    RewriteMap  deflector txt:/path/to/deflector.map
     
    RewriteCond %{HTTP_REFERER} !=”"
    RewriteCond ${deflector:%{HTTP_REFERER}} ^-$
    RewriteRule ^.* %{HTTP_REFERER} [R,L]
     
    RewriteCond %{HTTP_REFERER} !=”"
    RewriteCond ${deflector:%{HTTP_REFERER}|NOT-FOUND} !=NOT-FOUND
    RewriteRule ^.* ${deflector:%{HTTP_REFERER}} [R,L]
     

    … in conjunction with a corresponding rewrite map:

    ##
    ##  deflector.map
    ##
     
    http://www.badguys.com/bad/index.html    -
    http://www.badguys.com/bad/index2.html   -
    http://www.badguys.com/bad/index3.html   http://somewhere.com/
     

    This automatically redirects the request back to the referring page (when “-” is used as the value in the map) or to a specific URL (when an URL is specified in the map as the second argument).

    Other
    External Rewriting Engine
    Description:

    A FAQ: How can we solve the FOO/BAR/QUUX/etc. problem? There seems no solution by the use of mod_rewrite…

    Solution:

    Use an external rewrite map, i.e. a program which acts like a rewrite map. It is run once on startup of Apache receives the requested URLs on STDIN and has to put the resulting (usually rewritten) URL on STDOUT (same order!).

    RewriteEngine on
    RewriteMap    quux-map       prg:/path/to/map.quux.pl
    RewriteRule   ^/~quux/(.*)$  /~quux/${quux-map:$1}
     

    #!/path/to/perl
     
    #   disable buffered I/O which would lead
    #   to deadloops for the Apache server
    $| = 1;
     
    #   read URLs one per line from stdin and
    #   generate substitution URL on stdout
    while (<>) {
        s|^foo/|bar/|;
        print $_;
    }
     

    This is a demonstration-only example and just rewrites all URLs /~quux/foo/… to /~quux/bar/…. Actually you can program whatever you like. But notice that while such maps can be used also by an average user, only the system administrator can define it.
     
     


    18
    十一 07

    升级OpenBSD的ports

    建立一个cvsup-supfile文件,内容如下:

    #Defaults that apply to all the collections
    *default release=cvs
    *default delete use-rel-suffix
    *default umask=002
    *default host=cvsup.jp.openbsd.org
    *default base=/cvsup
    *default prefix=/cvsup

    #If your network link is T1 or faster, comment out the following line.
    *default compress

    OpenBSD-all
    #OpenBSD-src
    #OpenBSD-www
    #OpenBSD-ports
    #OpenBSD-x11
    #OpenBSD-xf4
    保存,
    # mg cvsup-supfile
    # cd /
    # mkdir cvsup
    # cd
    # cvusp –g –L 2 cvsup-supfile

    主要cvsup站点:
    cvsup.uk.openbsd.org]
    cvsup.de.openbsd.org
    cvsup2.de.openbsd.org
    cvsup.hu.openbsd.org
    cvsup.fr.openbsd.org
    cvsup.ca.openbsd.org
    cvsup.usa.openbsd.org
    cvsup.kr.openbsd.org
    cvsup.no.openbsd.org
    cvsup.pt.openbsd.org
    anoncvs.de.openbsd.org
    rt.fm
    skeleton.phys.spbu.ru
    cvsup.jp.OpenBSD.org
    mirror.osn.de
    openbsd.informatik.uni-erlangen.de

    OpenBSD-src   – The src repository
    OpenBSD-ports – The ports repository
    OpenBSD-www   – The www repository
    OpenBSD-x11   – The XFree86-3 repository
    OpenBSD-xf4   – The XFree86-4 repository
    OpenBSD-all   – All OpenBSD repositories