这段时间在对我们的棋牌系统做压力测试,模拟3000用户同时在线的状况。在这种情况下,数据库服务器的cpu消耗仅为2%左右(cpu是2*至强4核),内存占用1.8G(物理内存共有4G),大概平均每秒钟向数据库中插入40多条记录(三个表,包括游戏主从记录、利润记录等),还有数十次的select和update。另外,数据库中游戏记录表和利润记录这两个表的现有数据量都有1700万左右,当前数据库的总大小为37G。
在如此的情况下运行,cpu是比较平稳的,内存也很平稳,但是每当运行了11到14个小时左右的时候,系统就会产生很多Insert的Timeout日志。为此,我将命令执行的超时由30s改成60s,问题依旧存在。然后,我通过Profiler进行跟踪,发现每次Insert Timeout时,都会有大量的Audit login和Audit logout出现,我猜想,是不是到达高峰期的时候,由于很多局游戏同时结束而导致数据库连接不够用,于是,我将数据库连接池的MaxPoolSize由默认的100改成300,然后再次运行测试,十几个小时后,又出现了同样的问题。
看来,问题在于每隔一段时间,数据库就会执行一次耗时的动作,在这段时间,数据库提供给外部使用的性能就会急剧下降,从而导致Insert timeout。那么数据库每隔一段时间在执行什么动作了?备份?不可能,测试站上我们没有启用定时备份机制。最后终于发现,原来根源在于数据库空间的AutoGrowth,我们的数据库空间增长方案使用了默认的AutoGrowth,每次增长10%,当数据库发现余留空间不够时,它会自动申请磁盘空间,而这个过程是会影响到数据库的使用性能的,正是在这段时间,我们的Insert出现timeout了。
知道了问题根源,我们便试试禁用自动增长,然后一次性分配给数据库一个很大的空间,结果系统一直运行非常平稳和正常。我们可以使用系统存储过程sp_spaceused来查看数据库的空间使用状况。
对于那些可以定期停止运行来维护的系统,可以使用这种一次性分配大空间的方案来避免中途因为出现AutoGrowth而导致性能下降的情况,因为每次维护的时候,我们可以转移数据、或增加硬盘、或再次分配更大的空间等操作。
但是,如果是对于需要持续(比如365*24不间断)在高负载(比如CPU平均80%以上)下运行的数据库(并且不能出现任何timeout),该如解决空间增长问题了?望有经验朋友指点一二 :)
注:这只是我们一个初步的压力测试,Partition可以增加磁盘的IO吞吐量,肯定是要做的,而这次测试我要达到的目的是3000用户每天24小时都在线,所以没有所谓系统不忙的时候,这也是文章最后一个问题的基本假设。另外,如果真的是3000用户每天24小时在线,那么不到2个星期将跑满40g数据,而这40G数据当然是活跃的。我们已经通过缓存服务器、write-read分离(Master-Slave)等措施来减轻数据库的负担。