03 Jun

svn中的diff可以用vimdiff来代替

vimdiff是个很神奇的工具,用来看文件diff比diff程序直观太多了。

svn中查看diff的时候,也可以使用vimdiff用作diff program。

首先要写个脚本包装一下vimdiff:

#!/bin/sh

# Configure your favorite diff program here.
DIFF="/usr/bin/vimdiff"

# Subversion provides the paths we need as the sixth and seventh
# parameters.
LEFT=${6}
RIGHT=${7}

# Call the diff command (change the following line to make sense for
# your merge program).
$DIFF $LEFT $RIGHT

假设保存为/home/dongliu/mydiff,加上可执行权限,

chmod +x /home/dongliu/diffwrap

 

然后 修改~/.subversion/config文件中的配置,更改helpers下的diff程序配置:

[helpers]
diff-cmd = /home/dongliu/diffwrap

就可以在svn中使用vimdiff了。

27 Apr

mknod与重建/dev/null

mknod用来建立特殊文件节点,命令格式为:

mknod [OPTION]... NAME TYPE [MAJOR MINOR]

TYPE可以是c(字符型设备), b(block设备), p(管道),只有root用户才可以使用c,b类型的参数。-m参数可以指定创建文件的权限。如果/dev/null不小心被删除、覆盖了,或者由于某些原因损坏了,可以用mknod重建。
使用 ls -l /dev/null,可以看到一个正常的/dev/null文件:

crw-rw-rw-    1 root     root       1,   3 2003-01-30  /dev/null

这个说明,/dev/null是个字符设备,权限为666,MAJOR为1,MINOR为3。因而可以使用如下命令来recreate /dev/null:

rm -f /dev/null
mknod -m 666 /dev/null c 1 3

major device number和minor device number是由内核解释的,在<内核源码根目录>/Documentation/devices.txt文件中有说明。内核源码根目录通常为/usr/src/linux。
以这个/dev/null来说,type=c,major=1,minor=3代表的是Null device:

1 char    Memory devices
          1 = /dev/mem      Physical memory access
          2 = /dev/kmem     Kernel virtual memory access
          3 = /dev/null     Null device
          4 = /dev/port     I/O port access
          .....

其他很多特殊设备文件的原理和/dev/null是一样的。例如tty设备:

[root@bj19 root]# ls -l /dev/tty
crw-rw-rw-    1 root     root       5,   0 2003-01-30  /dev/tty
[root@bj19 root]# ls -l /dev/tty2
crw-------    1 root     root       4,   2  4月  8 08:34 /dev/tty2

13 Apr

今天手又发抖了

安装mysql的时候,敲chown mysql data/ –R, 很悲剧的敲成了chown mysql data / –R。一闪而过之后,所有文件的owner都变成mysql了。

之后检查机器,ssh不能登录,普通用户无法su到root。

幸好还有一个root帐号挂在上面,先把/bin/, /sbin/, /lib/这样的目录全部chown到root,其他目录下group为root的都chown到root,/home/下的文件夹该给谁给谁。一番折腾后ssh可以登录了,但是普通用户仍然无法su到root。

之前以为是文件属主的原因,现在看来不是了。错误提示是authorisation faild,瞅了一眼/bin/su 的stick位没了。于是chmod +s /usr/bin,终于把问题都解决了。

31 Dec

uni2ascii 编码/解码工具

我真傻,我以前没有发现这么个好用的东西,无奈的时候就自己上python逐个字符的转。

uni2ascii 可以实现汉字以及是其他unicode字符、html转义字符在以下的编码格式之间的转换:

HTML hexadecimal numeric character references, 例如&#x00E9;
HTML decimal numeric character references, 例如&#0233;
HTML character entities,例如&lt;
SGML hexadecimal numeric character references, 例如\#x00E9;
SGML decimal numeric character references, 例如\#0233;
\u-escaped hexadecimal, 例如\u00E9
RFC 2396 URI format, 浏览器URL编码使用的,例如%C3%A9;
RFC 2045 Quoted Printable, 例如=C3=A9

等等..总之常用的unicode转义形式,uni2ascii 都是支持的。
 

03 Dec

康神之bbs心得

原作者:kxn@bbs.Tsinghua.edu.cn / smth.org / bbs.newsmth.net
康神kxn的blog:kangkang.org 内含:康神之心得、发布Fterm最新版本、提交Fterm的bug
注:这是康神的一篇旧作,转载时请勿删除以上信息,以示对原作者kxn之尊重!谢谢!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
   我们现在提到的 BBS ,通常指的都是 Telnet BBS ,用一个 term 软件连接上,就可以看到文本的界面,比起如今花哨到无以复加的 WWW BBS 们来可谓是简陋到了极点,然而就是这样的 BBS,无数人每天面对它长达两位数小时还乐在其中,恐怕 UI 设计专家们知道也要气到吐血。也不时有人发表预言,预言 Telnet BBS 将很快消亡而被更加富有表现力的WWW BBS全面取代,只是年复一年,当年的预言者已经消失不见,BBS 上的用户数目却翻了一番又一番。。。这就是 Telnet BBS 的魅力。
Telnet BBS 系统数目众多,但是从根源找起,大致可以分成两大家族,Firebird BBS 和 Maple BBS,在大陆 Firebird BBS 的变种占据了绝对优势,在台湾地区则是 Maple BBS 的天下,由于台湾地区计算机发展历史比较长,因此 BBS 的人气也比大陆高,同时上站人数过万的站点有好几个,不过大陆毕竟有着人口优势,近年来教育网几大 BBS 的人数也迅速增长。下面我们就分别介绍这两大 BBS 家族。首先是在大陆最为流行的Firebird BBS ,最有名的 SMTH BBS, YTHT BBS,  Firebird 2000 三大流派都是由此而来。
很久很久以前,有那么一群大学生,也可能是科研机构的研究员什么的,他们整天在Unix主机上面打滚,觉得要是能在主机上面做一个论坛样的东西多好,于是他们就写了一个命令行程序,运行这个程序,操作者可以在界面下面留言,为了让多个人同时可以操作这个系统,他们把这个程序设置为系统某个用户的 shell ,每个 telnet 上该主机的用户,只要使用这个用户的用户名和密码登陆,就可以进行交流。这就是Internet BBS 的雏形。经过一段时间的发展,这个系统具有了相当多的交互功能,用户不仅可以留言,还可以互相发送信件,发送信息,看到同时在线的用户等等。

BBS 系统的开发者们为了让更多的人能使用这个系统并完善之,将BBS系统以开源协议发布于网络上面。只要拥有Unix主机,就可以取得源代码并安装BBS系统。因此BBS系统以很快的速度发展起来。在众多BBS系统中,某个叫做 Pirate BBS ,经过某些人修改后叫做  Eagle BBS 的分枝,流传入了台湾地区,交大资讯工程系从他发展出了Phoenix BBS,Phoenix BBS 是如今大部分中文 Telnet BBS 系统的祖先,然而它的名字却远不如其后辈响亮,在它的基础上由中正资工进一步修改的 BBS 系统,被赋予了那个大陆 BBS 开发者耳熟能详的名字 -- Firebird BBS。
   应该说, BBS 系统在传入台湾地区时候虽然功能还比较简陋,但是 BBS 系系统的基本架构已经定型,比如多进程模型,共享内存信息交换,利用系统信号来传递呼叫消息,用文件存储文章和索引等,这些设计在现在的 BBS 系统中大部分还在沿用,其中不少设计即使现在来看,也是相当标准有效的多进程 Unix 服务器设计。
   下面我们进入正文。
   Telnet BBS是一种流行于大学和研究机构中的电子公告牌系统,和时下流行的Web BBS系统不同,bbs的界面采用纯文本方式表现,用户使用终端软件连接bbs系统,文本界面在服务器端生成并发送出来,客户端软件仅原样显示文本内容,属于一种瘦客户机的应用。Telnet bbs (后面除非特殊提到,否则简称bbs)在台湾地区和大陆的教育网地区比较流行,比较大规模的站点在线人数一般都在万人以上。
   由于历史原因,bbs系统采用的是Unix下相当传统的1:1多进程模型,每进程处理一个连接的模型,此种模型的好处是服务相对比较稳定,不会因为一个用户出错导致整个系统的不可用,但是也带来耗费资源较多和进程之间通信比较困难的问题。Bbs服务器端的复杂逻辑也使得分布式设计很难实施。因此 bbs通常是单机承担几乎所有负载,大陆地区较大规模的bbs服务器上经常同时保持超过7000进程,台湾地区的bbs站甚至有并发20000进程以上的纪录。
   我们在维护大型bbs站点的过程中,积累了一些优化和维护如bbs这样高并发进程服务器的经验,考虑到1:1进程模型服务仍然有很广泛的应用,在这里写出和读者共享。

   优化服务器是综合性的工作,不仅需要修改代码,还需要调整系统参数,包含有很多琐碎的内容,根据目的来讲,大致可以根据节约资源的类型分为磁盘IO优化,内存优化,和CPU优化等几方面。下面介绍的优化思路虽然应用于bbs,但是也适用于其他应用系统。
1: 磁盘IO优化
磁盘IO优化可以说是服务器优化中最重要的一环,除了极少数的纯计算性应用,几乎所有的重载服务器最后都是卡在磁盘IO瓶颈上面。
a) 尽量使用shm等IPC手段而不是文件
多进程和多线程相比,最大的麻烦是不同执行环境交换信息不方便,因此很多程序员选择了使用文件交换信息,例如最早的bbs设计中,用户的帐户信息是存在于文件中的,进程从文件中读出内容,有修改后就写入文件。改进后的设计是将账号信息文件完整读入共享内存,所有修改都写入共享内存,然后由外部进程定时往磁盘上面同步。
甚至flock这样看起来不会造成太多IO的同步操作都应该尽量避免,原因是flock需要先open文件,而open 文件需要找到i节点,因此会占用文件系统的inode缓存空间,可能造成其他IO操作的性能降低。在很多情况下面需要的只是一个跨进程的mutex,可以使用0/1信号灯来实现。
b) 使用应用层缓存。
很显然,操作系统的缓存会受到很多因素的干扰,对于一些确定会经常访问的内容,例如版面的最新几片文章和最新列表,如果放入shm中缓冲,性能会有大幅度提升。
c) 尽量减少关键IO数据结构的大小
Bbs 文章列表的索引文件是由定长数据结构构成的,在这个数据结构中为了将来扩展方便,留下了很多保留域,造成了很多不必要的IO,删除不必要的域之后,数据结构变小了一半,减少了很多IO。很多时候,扩展性和性能其实是对立的,如果很需要性能,那么损失一定的扩展性也是不错的选择。
d) 避免在同一目录下放过多文件或者使用合适的文件系统
大部分文件系统对在同一目录中的文件列表采用线性存储,因此在一个目录下面存在很多文件的时候,打开文件变得非常的慢,因此通常要将文件根据某种规则散列到不同的子目录中,例如,文件 Atest 会被存放在 A/Atest ,如果文件太多,可能会需要对子目录下面的文件再次进行散列。
另一种解决文件过多影响效率的方法是使用有特殊优化的文件系统,例如Linux下的reiserfs。在这些文件系统中,目录中的文件列表是用平衡树来组织的,因此同一目录下面可以同时有数十万个文件而不会降低太多性能。
e) 根据系统的访问模式选择适合的硬件配置和系统参数
Bbs 系统使用零散的文件存放文章,它的访问模式基本是小文件随机读写,而文章数据相对比较重要,因此bbs使用strip大小比较小的raid5比较合适。文件系统选择专门为小文件优化的reiserfs,系统的预读长度也可以调小一些,Linux 默认的长度是 256K, 有些偏大。如果是大文件连续读写的话,那么raid的strip 大小和系统的预读长度应该放大,文件系统则尽量选择结构简单的文件系统例如ext2/3 等,如果数据并不是非常重要,那么甚至可以取消raid5,代之以raid0或者直接使用单独的硬盘。
2: 内存使用优化
BBS系统使用的多进程模式相当耗费内存,在bbs发展过程中,最早遭遇的瓶颈就是内存。减少内存的不必要浪费,可以节约出来作为系统缓存,从而间接提高更重要的IO性能
a) 尽量避免动态初始化常量,使用const说明将变量和常量区分开来。
Unix 系统在fork出新进程的时候,子进程和父进程共享相同的空间,之后按照COW机制,对修改的页面才进行复制操作,常量如果可以预先计算出来(例如一些转换表之类),就应该尽量避免在运行时动态初始化。另外因为只要修改一个字节,整个页面就都会被复制,因此应该避免常量和会被修改的变量混在一起,编译器本身会自动将不会被修改的内容放在一起,程序员需要做的事情,就是用const通知编译器哪些内容是不会被修改的。
b) 减小内存的峰值使用,特别是堆栈中内存
很多人习惯写程序时候在堆栈上声明一个比较大的临时数组,认为退出函数之后这部分内存会自动被释放。殊不知这样分配的内存并不会被动态被系统回收,因为系统并没有一个明显的标记可以得知堆栈内存是否还在使用中,特别是在多线程的环境下面,操作系统通常采用的措施是需要的时候分配页面,但是在进程退出之前并不回收。即使是通过malloc分配的堆内存,其页面是否回收也视库函数的实现而不确定。因此在无论什么情况下,贸然分配过大的内存,都会对性能造成一定的影响。
c) 如有可能,尽量使用shm来保证页面一定会被多个进程共享。
3: CPU优化
这里说的CPU使用优化,不包括像使用hash来代替线性查找这类最基本的算法优化,而是涉及一些和系统关系比较密切的操作。
a) 使用针对硬件优化的编译器
这应该是所有CPU相关优化中最容易做到也是最容易看到效果的,Intel CPU的Linux系统上面使用 Intel C/C++ 编译器,可以获得很好的效果,甚至AMD的Athlon系列CPU也能获得一定程度的加速。。Bbs进站时候需要初始化很多内容,计算量比较大,使用gcc 时候负载在4左右,使用icc编译以后负载马上下降到1以下。推荐编译时候针对特定CPU指令集优化并且打开跨文件优化选项(-ipo)
b) 使用单独进程来初始化和维护共享内容,避免出现竞争导致逻辑错误
严格讲这并不能提升很多性能,只是为了减少多进程服务器上面经常出现的逻辑错误。在原始的bbs设计中,共享资源的创建是由第一个访问的进程在打开失败时候创建的,但是重负载服务器上面有时候打开也会失败,从而导致多次创建共享资源。
c) 序列化容易导致负载上升的行为
BBS进程在进站时候需要进行很多的初始化工作,同样进程退出的时候也要做很多的收尾工作,此时对CPU或者IO的占用比较大,通过一个互斥锁可以使多个进程不要同时进行这些操作,否则系统负载有可能上升到一定程度引起正反馈,导致系统彻底崩溃。
d) 尽量减少信号的使用
Unix系统下面对于信号的实现的代价是比较大的,同时信号本身也很容易导致处理逻辑的混乱。高负载服服务器应该尽量减少信号的使用。
e) 对于大范围IO读取操作,使用mmap调用
使用mmap操作比传统的read操作好处是减少了一次内核态到用户态的拷贝。在大范围IO操作的时候具有优势,bbs中使用mmap操作来在文件中搜索内容,速度最高时候提高了5倍左右。但是需要注意的是,mmap并不适用于有写入的情况,因为mmap写盘的时候是以页为单位进行操作,页中只要有一个字节被改写,就要往磁盘上面写整个页面的数据,无端增加了IO量。
以上是我们在维护大型bbs站点时积累的一些经验,供各位读者参考。

08 Sep

linux憎恨手册-2

linux总是能让你感到惊奇……
当时,我只是输入crontab没加参数直接回车,发现不对后,顺手按了一个Ctrl+D,于是事情就这样发生了。
crontab竟然被清空了!哪怕一点点提示都没有给!而且这个crontab只有一个年代久远的备份。。心慌啊,谁知道漏了一个什么关键定的时任务,会造成多大的影响。
幸好后来发现系统/var/log/下有crontab运行的日志,写了脚本把里面的语句抠出来,一个个核对时间,再加到crontab里去。
在linux系统,对任何东西做更改之前,一定要保证有备份!通常这能弥补你所犯下50%的错误……
30 Jul

linux憎恨手册

在linux下,任何事情都可能发生,所以脑袋是一定要清醒的,手是绝对不能够抖的。比如昨天下午,在我自己的主目录下,执行了rsync auv --delete,然后就看见唰唰的滚屏,主目录下的所有文件都被删除了,被一堆乱七八糟的图片代替了……这时候脑袋依然不清醒,没有意识到我ssh的pub key也被删除了,直接退出securecrt。然后,再次登录的时候悲剧的发现登不上自己的服务器了。
29 Jul

bash下delete、pagedown等键不好使的问题

Bash中,经常按下键盘上的Home, Del, Insert键之后,只会输入一些奇妙的字符,我们可以通过编辑inputrc文件来修正这个问题:
在/etc/profile中加入:
export INPUTRC=/usr/local/etc/inputrc
在/usr/local/etc/inputrc中写入:
vi /usr/local/etc/inputrc
set meta-flag on
set input-meta on
set convert-meta off
set output-meta on

"\e[1~": beginning-of-line
"\e[4~": end-of-line
"\e[5~": beginning-of-history
"\e[6~": end-of-history
"\e[3~": delete-char
"\e[2~": quoted-insert
"\e[5C": forward-word
"\e[5D": backward-word
29 May

shell脚本模拟多进程

shell脚本中开多个进程没什么困难,需要解决的问题是怎么控制同时运行的进程数目。为此,创建一个命名管道(fifo),在初始时,向其中灌入SUB_PROCESS_NUM行数据,SUB_PROCESS_NUM为并发的进程数。每个子进程在运行钱,从fifo中读入一行数据,如果fifo中已经北邮数据的话,进程就被阻塞在read操作上;子进程运行结束后,想fifo中灌入一行数据,这样下个进行就可以运行了。

一个例子如下,run函数代表子进程的操作:

Bash语言:
#!/bin/bash

SUB_PROCESS_NUM=10

tmpfile="$$.fifo"
mkfifo $tmpfile
exec 6<>$tmpfile
rm -f $tmpfile
for((i=1;i<=10;i++));do echo "init sub job $i.";done >&6


function run(){
    sleep 100;
}

for ((i=0;i<100;i++)); do
    read line
    echo "$line"
    (run; echo "sub job $i finished.") >&6 &
done <&6

以前工作的时候经常需要从几百台机器拷贝数据,如果一台一台的拷贝要话很长时间,所有的机器一起拷贝的话对拷贝到的目标机器压力又很大,就拿这中方法来跑了。

17 Dec

BASH 中的字符串处理(转)

得到长度

 
%x="abcd"
#方法一
%expr length $x
4
# 方法二
%echo ${#x}
4
# 方法三
%expr "$x" : ".*"
4
# expr 的帮助
# STRING : REGEXP   anchored pattern match of REGEXP in STRING
查找子串
 
%expr index  $x "b"
2
%expr index  $x "a"
1
%expr index  $x "b"
2
%expr index  $x "c"
3
%expr index  $x "d"
4
得到子字符串
 
# 方法一
# expr <string> startpos length
%expr substr "$x" 1 3
abc
%expr substr "$x" 1 5
abcd
%expr substr "$x" 2 5
bcd
# 方法二
# ${x:pos:lenght}
%echo ${x:1}
bcd
%echo ${x:2}
cd
%echo ${x:0}
abcd
%echo ${x:0:2}
ab
%pos=1
%len=2
%echo ${x:$pos:$len}
bc
匹配正则表达式
 
# 打印匹配长度
%expr match $x "."
1
%expr match $x "abc"
3
%expr match $x "bc"
0
字符串的掐头去尾
 
%x=aabbaarealwwvvww
%echo "${x%w*w}"
aabbaarealwwvv
%echo "${x%%w*w}"
aabbaareal
%echo "${x##a*a}"
lwwvvww
%echo "${x#a*a}"
bbaarealwwvvww
其中 , # 表示掐头, 因为键盘上 # 在 $ 的左面。
其中 , % 表示%,  因为键盘上 % 在 $ 的右面。
单个的表示最小匹配,双个表示最大匹配。
也就是说,当匹配的有多种方案的时候,选择匹配的最大长度还是最小长度。

字符串的替换
 
%x=abcdabcd
%echo ${x/a/b} # 只替换一个
bbcdabcd
%echo ${x//a/b} # 替换所有
bbcdbbcd
不可以使用 regexp , 只能用 * ? 的文件扩展方式。

共22篇,第1/3页 首页 1 2 3 下一页 尾页