Freeshell IPv6 更换地址段、升级到千兆

原来 freeshell 没有自己的 IPv6 地址段,访问经常不稳定,还是百兆的。现在从 jameszhang 申请了独享 IPv6 地址前缀 2001:da8:d800:71::/64,与 IPv4 网络一样升级到千兆接入。如果你的 shell ID 是 101,则独享 IPv6 地址就是 2001:da8:d800:71::101,其中 2001:da8:d800 是科大 IPv6 地址前缀,71 是 freeshell,好记吧!

控制面板界面也相应更新,把 IPv6 地址作为首选,ssh 不再需要非标准端口号了,freeshell 上也可以尽情开放你喜欢的端口。

freeshell-curr

如果 IPv6 地址不能从外面连进去,有可能是邻居发现协议的问题,请用 IPv4 ssh 登录,在 freeshell 里执行 ping6 bbs6.ustc.edu.cn,一般就能通了。如果从里向外都不通,或者从里向外通但从外向里不通,请联系 lug AT ustc.edu.cn。

原来的 2001:da8:d800:701:8000 开头的 IPv6 地址仍然可用,不过以后请尽量使用新 IPv6 地址。在同一网卡上两个 IPv6 地址各种条件都相同的情况下,内核会选择后添加的 IPv6 地址作为默认源IP(这与 IPv4 选择网卡的第一个IP有所不同),因此无需删除原来的IP地址。

留个纪念,更新前的控制面板:

freeshell-prev

修复 mirrors 缓存过期问题

mirrors 的源有一些没有更新,原因是使用了过期的 SSD cache。SSD cache 本来会与源目录同步,不幸的是 SSD 满了。撑满 SSD 的原因是同步时没有删除已经不在缓存文件列表中的文件,这又是因为我对

rsync --delete --file-list

的理解有误。我以为这样会删除源目录中不在 file-list 中的文件,事实上不会。

改成了根据缓存文件列表生成符号链接到临时目录,再同步文件到 SSD:

rsync --delete --copy-links $TMP_LINK_ROOT/ $SSD_CACHE_ROOT/

commit: https://gitgeek.net/mirrors/ssd-cache/commit/6602b3b47d55d47d2185a9ed8ad1220a54cd905a

服务器优化 TCP 参数

blog 和 mirrors 服务器调整了 ip_conntrack 配置:

net.ipv4.netfilter.ip_conntrack_max=655360

# should not be less than net.ipv4.tcp_keepalive_time (default 7200)
net.netfilter.nf_conntrack_tcp_timeout_established=14400

blog,mirrors 和 gitlab 调整了 TCP 发送窗口大小限制,以充分利用高延迟和高带宽的线路:

net.core.wmem_max=12582912
net.core.rmem_max=12582912
net.ipv4.tcp_rmem= 10240 87380 12582912
net.ipv4.tcp_wmem= 10240 87380 12582912

blog,mirrors 和 gitlab 在 HTTP 持久连接期间不再慢启动,以加快第二次及以后访问页面:

net.ipv4.tcp_slow_start_after_idle=0

增加 TCP 发送和接收默认窗口大小到 10 个 MSS,以减少小 HTTP 请求和 HTTPS 握手的来回次数。对 2.6.33 以下内核只能调整默认发送窗口大小(以下命令仅为示例):

# example on Debian wheezy
ip route change default via 202.141.176.126 initrwnd 10 initcwnd 10
# example on Debian squeeze
ip route change default via 202.141.176.126 initcwnd 10

Freeshell 添加重装系统功能

千呼万唤始出来,freeshell.ustc.edu.cn 终于可以重装系统了。

reinstall

重装系统的步骤:

  1. 登录 http://freeshell.ustc.edu.cn
  2. 点击 Reinstall System(如上图)
  3. 在弹出的对话框中点击确认
  4. 查邮件,点击邮件中的确认链接,执行重装操作
  5. 等1分钟再查邮件,应该会收到重装后 freeshell 的 root 密码
  6. 尝试 ssh,应该会提示 conflicting keys 之类的错误
  7. 按照 ssh 的提示删除 ~/.ssh/known_hosts 中的冲突行,重试 ssh
  8. 登录后,尽快修改 root 密码

Mirrors 扩充磁盘阵列空间

为了给即将入驻的 sourceforge 源腾地方,mirrors 将磁盘阵列的 XFS 扩充到 24T,现有 14T 可用空间。

删除无用内容

首先删除一些未同步成功又占据大量空间的源,释放了约 3T 磁盘空间。

  • android-src
  • android-releases
  • sourceforge
  • google-v8
  • chromiumos

扩容 XFS

XFS 号称能在线扩容,不过那是在 XFS 建立在 LVM 上时才可以。由于害怕 LVM 影响性能,mirrors 的 XFS 是直接建立在磁盘阵列的 GPT 上的。扩容 XFS 分为三步:

  1. 修改分区表
  2. 让内核重新载入分区信息,而这需要卸载文件系统
  3. 在线扩容 XFS

卸载磁盘阵列文件系统

以往卸载磁盘阵列的文件系统是全手工操作,折腾一次至少要十几分钟,其间磁盘阵列上的源都无法访问,整个网络服务(nginx 等)也会有一两分钟中断。这次我们使用了脚本,基本服务(nginx)每次中断时间不超过5秒,磁盘阵列的中断时间不超过2分钟(第一次中断了1分多钟是由于脚本里忘了 mount -a 重新挂载,收到报警短信后赶紧 mount -a)。

  1. 停止 LXC(因为 LXC 的根文件系统在磁盘阵列上)
  2. 杀掉所有服务进程
  3. 卸载已挂载的磁盘阵列文件系统(如果这一步出现问题,需要用 lsof 排查)
  4. 做想做的事
  5. 重新挂载文件系统
  6. 启动服务进程
  7. 启动 LXC

一开始的脚本是这样的:

sudo service rsync stop; sudo service vsftpd stop; sudo service nginx stop; mount | grep /dev/sdh1 | awk '{print $3}' | while read dir; do sudo umount $dir; sudo lsof $dir; done; sudo service nginx start; sudo service vsftpd start; sudo service rsync start

但发现 lsof 里还有很多 rsync 和 vsftpd 占着文件描述符,因此把 vsftpd 和 rsync 改成了杀气腾腾的 pkill:

sudo service nginx stop; sudo pkill vsftpd; sudo pkill rsync

还是有一些 rsync 进程发了 SIGTERM 信号仍无动于衷,因此改成了 SIGKILL(kill -9 所用的不可捕获杀进程信号)。

sudo service nginx stop; sudo pkill vsftpd; sudo pkill -SIGKILL rsync

现在 umount 成功了,但 rsync 启动失败了。这是由于没有删掉 rsyncd 的 pid 文件,强制删除即可。

sudo service nginx stop; sudo pkill vsftpd; sudo pkill -SIGKILL rsync; mount | grep /dev/sdh | awk '{print $3}' | while read dir; do sudo umount $dir; done; sudo service nginx start; sudo service vsftpd start; sudo rm -f /var/run/rsyncd.pid; sudo service rsync start

坑爹的 udev rule

扩容顺利完成了,不过 partprobe 之后,sdh 变成了跟 sdh1 一样的大小,分区表也不见了。重新启动 iscsi,问题依然如故。

$ sudo service nginx stop; sudo pkill vsftpd; sudo pkill -SIGKILL rsync; mount | grep /dev/sdh | awk '{print $3}' | while read dir; do sudo umount $dir; done; sudo /etc/init.d/open-iscsi restart; sudo service nginx start; sudo service vsftpd start; sudo rm -f /var/run/rsyncd.pid; sudo service rsync start
Stopping nginx: nginx.
Unmounting iscsi-backed filesystems: Unmounting all devices marked _netdev.
Disconnecting iSCSI targets:Logging out of session [sid: 1, target: iqn.2002-10.com.infortrend:raid.sn8223150.001, portal: 192.168.10.1,3260]
Logout of [sid: 1, target: iqn.2002-10.com.infortrend:raid.sn8223150.001, portal: 192.168.10.1,3260] successful.
.
Stopping iSCSI initiator service:.
Starting iSCSI initiator service: iscsid.
Setting up iSCSI targets:
Logging in to [iface: default, target: iqn.2002-10.com.infortrend:raid.sn8223150.001, portal: 192.168.10.1,3260] (multiple)
Login to [iface: default, target: iqn.2002-10.com.infortrend:raid.sn8223150.001, portal: 192.168.10.1,3260] successful.
.
Mounting network filesystems:.
Starting nginx: nginx.
Starting FTP server: vsftpd.
Starting rsync daemon: rsync.

$ sudo fdisk -l /dev/sdh

Disk /dev/sdh: 24189.3 GB, 24189254763008 bytes
255 heads, 63 sectors/track, 2940842 cylinders, total 47244638209 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/sdh doesn't contain a valid partition table

$ sudo fdisk -l /dev/sdh1

Disk /dev/sdh1: 24189.3 GB, 24189254763008 bytes
255 heads, 63 sectors/track, 2940842 cylinders, total 47244638209 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00000000

Disk /dev/sdh1 doesn't contain a valid partition table

线索在 syslog 里:

udevd[13846]: kernel-provided name 'sdh1' and NAME= 'sdh' disagree, please use SYMLINK+= or change the kernel to provide the proper name

原来是下面的 udev rule 捣的鬼,内核把 sdh1 和 sdh 都 probe 出来了,sdh1 占用了 sdh 这个名字(因为它们都符合 udev rules,不信可以自己执行 /lib/udev/scsi_id 验证)……

$ cat /etc/udev/rules.d/80-persistent-iscsi.rules
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM="/lib/udev/scsi_id --whitelisted --replace-whitespace /dev/$name", RESULT=="3600d0231000da93e75966be33fd9a2b4", NAME="sdh"

修改方法很简单,加个 %n 就行了。

$ cat /etc/udev/rules.d/80-persistent-iscsi.rules
KERNEL=="sd*", SUBSYSTEM=="block", PROGRAM="/lib/udev/scsi_id --whitelisted --replace-whitespace /dev/$name", RESULT=="3600d0231000da93e75966be33fd9a2b4", NAME="sdh%n"

扩容过程演示

下面我们演示将磁盘阵列 XFS 从 22T 扩容到 24T 的完整过程(为了文章清晰,删除了一些输出)。

1. 查看分区表信息。GPT 分区表要用 gdisk,而非 fdisk。

[email protected]:~$ sudo gdisk /dev/sdh
GPT fdisk (gdisk) version 0.8.5

Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present

Found valid GPT with protective MBR; using GPT.

Command (? for help): i
Using 1
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft basic data)
Partition unique GUID: 4592A37B-886C-40C9-A2AC-D9145B1D33D1
First sector: 2048 (at 1024.0 KiB)
Last sector: 47244640256 (at 22.0 TiB)
Partition size: 47244638209 sectors (22.0 TiB)
Attribute flags: 0000000000000000
Partition name: 'array'

2. 删除原有分区并新建分区、修改分区名称。注意分区起始扇区、GUID 都必须与原来的相同,否则文件系统无法识别!

Command (? for help): d 1
Using 1

Command (? for help): n
Partition number (1-128, default 1):
First sector (34-54684213214, default = 2048) or {+-}size{KMGTP}:
Last sector (2048-54684213214, default = 54684213214) or {+-}size{KMGTP}: 24T
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): EBD0A0A2-B9E5-4433-87C0-68B6B72699C7
Changed type of partition to 'Microsoft basic data'

Command (? for help): c 1
Using 1
Enter name: array

Command (? for help): i
Using 1
Partition GUID code: EBD0A0A2-B9E5-4433-87C0-68B6B72699C7 (Microsoft basic data)
Partition unique GUID: A5298F7D-A675-41DD-9AA3-BE119CA73DB3
First sector: 2048 (at 1024.0 KiB)
Last sector: 51539607552 (at 24.0 TiB)
Partition size: 51539605505 sectors (24.0 TiB)
Attribute flags: 0000000000000000
Partition name: 'array'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): Y
OK; writing new GUID partition table (GPT) to /dev/sdh.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot.
The operation has completed successfully.

3. 卸载磁盘阵列文件系统以便 partprobe 让内核重新载入分区表(详见上文)

[email protected]:~$ sudo lxc-list
RUNNING
  lxr
  pypi
  sync (auto)

[email protected]:~$ sudo lxc-stop -n pypi
[email protected]:~$ sudo lxc-stop -n sync
[email protected]:~$ sudo lxc-stop -n lxr

[email protected]:~$ sudo service nginx stop; sudo pkill vsftpd; sudo pkill -SIGKILL rsync; mount | grep /dev/sdh | awk '{print $3}' | while read dir; do sudo umount $dir; done; sudo partprobe; sudo mount -a; sudo service nginx start; sudo service vsftpd start; sudo rm -f /var/run/rsyncd.pid; sudo service rsync start
Stopping nginx: nginx.
Starting nginx: nginx.
Starting FTP server: vsftpd.
Starting rsync daemon: rsync.

[email protected]:~$ sudo lxc-start -n pypi -d
[email protected]:~$ sudo lxc-start -n sync -d
[email protected]:~$ sudo lxc-start -n lxr -d

4. 检查分区信息,使用 xfs_growfs 对 XFS 分区进行扩容。

[email protected]:~$ sudo gdisk -l /dev/sdh
GPT fdisk (gdisk) version 0.8.5

Partition table scan:
MBR: protective
BSD: not present
APM: not present
GPT: present

Found valid GPT with protective MBR; using GPT.
Disk /dev/sdh: 54684213248 sectors, 25.5 TiB
Logical sector size: 512 bytes
Disk identifier (GUID): 5E620981-EBFB-4EEA-BCF9-0052707F6859
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 54684213214
Partitions will be aligned on 2048-sector boundaries
Total free space is 3144607676 sectors (1.5 TiB)

Number Start (sector) End (sector) Size Code Name
1 2048 51539607552 24.0 TiB 0700 array

[email protected]:~$ sudo xfs_growfs /dev/sdh1
meta-data=/dev/sdh1 isize=256 agcount=22, agsize=268435455 blks
= sectsz=512 attr=2
data = bsize=4096 blocks=5905579776, imaxpct=5
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0
log =internal bsize=4096 blocks=521728, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 5905579776 to 6442450688

5. 检查扩容是否成功。

[email protected]:~$ df -lh /dev/sdh1
Filesystem Size Used Avail Use% Mounted on
/dev/sdh1 24T 11T 14T 43% /srv/ftp/ubuntu-old-releases

[email protected]:~$ sudo lxc-list
RUNNING
  lxr
  pypi
  sync (auto)

FROZEN

STOPPED
  mirror-lab
  mirror-lab_
  php-mirror
  root

最后提醒 mirrors 维护者,这类危险操作必须在 screen 或 byobu(screen 的封装,可以有选项卡)中进行,以免你的网络突然中断,脚本被 SIGHUP,将系统留在不可预测的状态。

Blog 修改ISP线路

发现 blog 服务器通过移动线路访问某些国内小运营商的速度很慢。现在 DNS 配置改成与 mirrors 一样,即移动、铁通、国外走移动线路,其余走电信线路。出站路由改为国外和移动走移动线路,其余走电信线路。

LUG FTP, TimeMachine, Ganglia 恢复

lug 服务器服务已经恢复,DNS 已经从备份站点切换回去,LUG 主页、FTP、Ganglia 服务已恢复正常。TimeMachine 应该也恢复了,求测试。

本次故障是 dist-upgrade引起, sudoers 语法错误致使无法远程修复,又赶上国庆假期,无法进入机房接触机器进行快速修复,一直拖到10月10日。

详细报告请见http://lug.ustc.edu.cn/wiki/user/vastuniverse/lug-upgrade-failure

mirrors 启用 SSD cache

优化之前,mirrors 磁盘阵列(sdh)的 io util 常常在 90% 以上,有些时候甚至“稳定”在 100%。从sda 往 sdh 复制一些小文件,竟然不到 5MB/s。尝试调整了 iscsi 的 MTU、txqueuelen 等网络参数,没有效果,瓶颈可能不在网络上。以一块 7500rpm SATA 磁盘随机读 75~100 iops 计算,RAID6 的 iops 大约是 450~600 iops,与我们的测试结果基本相符,因此磁盘阵列可能本来就这么慢。

SSD(/dev/sdb)被格式化为 ext4 文件系统(UUID=8e19059d-358e-41ca-8896-b9b26a2d4f59),用 tune2fs 去掉了 journal。挂载参数为 nodev,nosuid,noatime,discard,挂载点为 /mnt/ssd。

用 fio 测试结果如下(使用 1G 文件):

  • 连续读 139327KB/s,34831 iops
  • 连续写 1001.1MB/s,256500 iops
  • 同时连续读写,与单独测试相比没有明显变化
  • 随机读 15708KB/s,3926 iops
  • 随机写 762047KB/s,190511 iops
  • 同时随机读写,与单独测试相比没有明显变化

写的性能这么好,估计是由于 buffer。连续读性能不高,是因为 SSD 在 RAID 卡后面,不过对我们来说足够了。我们最关心的随机读性能 3926 iops 达到了预期,目前磁盘阵列的随机读性能不到 500 iops。

SSD cache 的缓存策略基于 HTTP access log。每天凌晨,选出前一周的 HTTP 200 请求,按照 URL 访问频率降序排序,填满 SSD cache 为止。

注册登录 USTC LUG GitLab,即可查看源代码:https://gitgeek.net/mirrors/ssd-cache

cron-cache.sh 每天运行一次,生成缓存:

  1. 读出最近7天的 HTTP access log
  2. 取出 200 请求,统计 URL 访问频率
  3. 筛选至少访问过2次的文件,按频率降序排序,得到 filefreq-20131010.gz 这样的文件列表。
  4. 从上述文件列表中依次取出文件,获取其大小,添加到缓存列表(tocache-20131010)中,直到达到设定的缓存总大小。
  5. 用 rsync 把缓存列表中的文件同步到缓存区。用 rsync 的好处是文件没有被修改时不需要重新复制,由于多数文件的访问频率是相对稳定的,每天复制的数据量并不大。

每个源同步后,要刷新 cache,这是 update-cache.sh 的职责。它同样使用了 rsync。

200G 的缓存共缓存了 3696 个文件(其中 iso 文件占 422 个),根据前7天的 HTTP 200 日志,最多的在7天内被访问了 1036142 次,最少的在7天内被访问了 97 次。

SSD cache 的效果怎么样呢?200G 的 cache 同步完成后,

  • 磁盘阵列(sdh)的负载从一直 90%+,降到了时而 90%+,时而 50%~60%
  • 总流量增加了约 50Mbps(原来是 ~350 Mbps,后来是 ~400 Mbps)
  • load average 似乎没有明显变化
  • 被缓存文件的校内下载速度可达 50~70 MB/s,能够吃满 mirrors 的千兆网卡

希望 status.lug.ustc.edu.cn 和 mirrors 的 collectd-web 尽快恢复,以便对 SSD 的效果做更多更直观的观察和评估。