性能优化
ytht bbs是目前中国大陆教育网内较领先的bbs系统之一,一塌糊涂代码的负载能力高于平 均水平,并且其功能较为齐备,集成了telnet,ssh,www,ftp,pop3等服务。
在2003年3月14日的版本下,ytht.net 系统负荷小于 1
参考系统配置:P3 866 2; 2.5G sdram; 18G2+36G*1 SCSI; no raid; 在线人数高峰 4400人。系统服务包括附件下载流畅无停滞。
BBS 的系统架构决定了它只能运行在单机上。YTHT 技术开发组还是做了不少优化的工作。
Telnet 性能优化
阅读 doc/INSTALL.chinese
文件,里面有几行代码:
[root]# mount none /home/bbs/bbstmpfs -t tmpfs -o size=128m
[bbs]$ cd /home/bbs
[bbs]$ ln -s /home/bbs/bbstmpfs/tmp tmpfast
[bbs]$ ln -s /home/bbs/bbstmpfs/dynamic dynamic
tmpfs是一种虚拟内存文件系统,是基于内存的文件系统,Linux 中可以把一些程序的临时文件放置在tmpfs中,利用tmpfs比硬盘速度快的特点提升系统性能。07年我在某公司工作的时候,发现给腾讯 QQ 空间做加速时,也是这么干的,把几个G的静态资源小文件加载到内存中,以空间换时间。
CGI 性能优化
www 服务使用了 Apache的两个模块:
- Apache(1.3) fastrw 模块
- Apache(2.0) fastcgi 模块,提高 cgi 的执行效率。
为了优化性能以及定制化开发,Apache 最后都需要手动修改编译代码,具体见 software/apachelimit.patch
与 software/fastcgi_bufsize.patch
在当时看来是不错的选择。目前 Lighttpd 与 Nginx 拥有比 Apache 有更好的性能,特别是针对文件下载。
重负载Telnet BBS系统优化和维护经验谈
作者:[email protected] / smth.org / bbs.newsmth.net
神说,要有光,于是有了光;
神说,要灌水,于是有了BBS……
我们现在提到的 BBS ,通常指的都是 Telnet BBS ,用一个 term 软件连接上,就
可以看到文本的界面,比起如今花哨到无以复加的 WWW BBS 们来可谓是简陋到了极点,
然而就是这样的 BBS,无数人每天面对它长达两位数小时还乐在其中,恐怕 UI 设计专
家们知道也要气到吐血。也不时有人发表预言,预言 Telnet BBS 将很快消亡而被更加
富有表现力的WWW BBS全面取代,只是年复一年,当年的预言者已经消失不见,BBS 上的
用户数目却翻了一番又一番。。。这就是 Telnet BBS 的魅力。
Telnet BBS 系统数目众多,但是从根源找起,大致可以分成两大家族,Firebird B
BS 和 Maple BBS,在大陆 Firebird BBS 的变种占据了绝对优势,在台湾地区则是 Ma
ple BBS 的天下,由于台湾地区计算机发展历史比较长,因此 BBS 的人气也比大陆高,
同时上站人数过万的站点有好几个,不过大陆毕竟有着人口优势,近年来教育网几大 B
BS 的人数也迅速增长。下面我们就分别介绍这两大 BBS 家族。首先是在大陆最为流行
的 Firebird BBS ,最有名的 SMTH BBS, YTHT BBS, Firebird 2000 三大流派都是由
此而来。
很久很久以前,有那么一群大学生,也可能是科研机构的研究员什么的,他们整天
在Unix主机上面打滚,觉得要是能在主机上面做一个论坛样的东西多好,于是他们就写
了一个命令行程序,运行这个程序,操作者可以在界面下面留言,为了让多个人同时可
以操作这个系统 ,他们把这个程序设置为系统某个用户的 shell ,每个 telnet 上该
主机的用户,只要使用这个用户的用户名和密码登陆,就可以进行交流。这就是 Inter
net BBS 的雏形。经过一段时间的发展,这个系统具有了相当多的交互功能,用户不仅
可以留言,还可以互相发送信件,发送信息,看到同时在线的用户等等。
BBS 系统的开发者们为了让更多的人能使用这个系统并完善之,将BBS系统以开源协
议发布于网络上面。只要拥有Unix主机,就可以取得源代码并安装BBS系统。因此BBS系
统以很快的速度发展起来。在众多BBS系统中,某个叫做 Pirate BBS ,经过某些人修改
后叫做 Eagle BBS 的分枝,流传入了台湾地区,交大资讯工程系从他发展出了 Phoen
ix BBS,Phoenix BBS 是如今大部分中文 Telnet BBS 系统的祖先,然而它的名字却远
不如其后辈响亮,在它的基础上由中正资工进一步修改的 BBS 系统,被赋予了那个大陆
BBS 开发者耳熟能详的名字 -- Firebird BBS。
应该说, BBS 系统在传入台湾地区时候虽然功能还比较简陋,但是 BBS 系统的基本
架构已经定型,比如多进程模型,共享内存信息交换,利用系统信号来传递呼叫消息,
用文件存储文章和索引等,这些设计在现在的 BBS 系统中大部分还在沿用,其中不少设
计即使现在来看,也是相当标准有效的多进程 Unix 服务器设计。
下面我们进入正文。
Telnet BBS是一种流行于大学和研究机构中的电子公告牌系统,和时下流行的Web B
BS系统不同,bbs的界面采用纯文本方式表现,用户使用终端软件连接bbs系统,文本界
面在服务器端生成并发送出来,客户端软件仅原样显示文本内容,属于一种瘦客户机的
应用。Telnet bbs (后面除非特殊提到,否则简称bbs)在台湾地区和大陆的教育网地区
比较流行,比较大规模的站点在线人数一般都在万人以上。
由于历史原因,bbs系统采用的是Unix下相当传统的1:1多进程模型,每进程处理一个
连接的模型,此种模型的好处是服务相对比较稳定,不会因为一个用户出错导致整个系
统的不可用,但是也带来耗费资源较多和进程之间通信比较困难的问题。Bbs服务器端的
复杂逻辑也使得分布式设计很难实施。因此bbs通常是单机承担几乎所有负载,大陆地区
较大规模的bbs服务器上经常同时保持超过7000进程,台湾地区的bbs站甚至有并发2000
0进程以上的纪录。
我们在维护大型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下的rei
serfs。在这些文件系统中,目录中的文件列表是用平衡树来组织的,因此同一目录下面
可以同时有数十万个文件而不会降低太多性能。
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站点时积累的一些经验,供各位读者参考。