压力测试遇到的一些问题

资源耗尽

##句柄耗尽
在以往的一个桌面程序项目中,遇到一个有意思的事情。项目的目标是在用户有系统运行的时候进行弹窗报警。正常情况下我们是收到一个报警,就弹一个窗进行显示。然后用户点击弹窗表示已经明确,弹窗关闭。本来流程好好的没问题,但是真正运行的时候才发现,工作站运行的时候,用户并不会立即操作。有可能十天半个月才操作一次。等用户来操作时,发现满屏幕的弹窗,这种体验感非常不好;于是我们第一次想着先把报警给存起来,只保留一定数量的报警给用户,等用户操作关闭报警的时候,再从缓存中的报警拿一个最新存储的报警出来生成弹窗。这种方法运行了一段时间也没问题。但是呢用户又提出了关闭报警弹窗时需要用户登录,用以方便记录是谁关闭弹窗。所以用户未登录之前的报警需要存起来,等用户登录的时候,再从缓存拿一定数量的报警进行弹窗。可是现场运行的时候发现长时间未登录突然登录的时候,软件会卡死,并且弹窗并不是规定的数量。是什么原因导致的呢?原来是因为长时间未登录,缓存中存在大量报警(至少几千个),而我们限制弹窗数量的方法是根据当前已经弹出的弹窗数量来做的。由于在从报警缓存中取出报警进行弹窗的速度比较慢,而他们又是异步的。结果就导致在极短时间内瞬间从缓存中取出全部报警进行弹窗。几千个弹窗一直在申请资源,消耗进程的句柄和用户对象。正常操作系统分配给一个进程的用户对象大概是1万个,而一个窗体消耗4个用户对象。所以当弹窗至2500个左右时就会导致资源耗尽,程序界面卡死。后来直接定义一个实数对象来计算,成功的限制了弹窗的数量。归根揭底这个问题出现的原因就是异步处理,并且ui对象生成速度比较慢导致的。
##线程耗尽
同样是这个报警系统,另外一个事情就是报警保存发生的意外情况。报警在产生后,系统会将该报警保存到数据库。但是数据库保存不上时,我们会将报警保存到本地的sqllite数据库中。保存的方式就是来一个报警我们放到线程池的共享线程中执行insert操作。正常情况下,我们测试是没问题的。但是到了现场运行发现,软件没法正常工作。后来查了半天发现是特殊情况下,大量报警会同时到来,每个报警都会占用一个共享线程,并且这个线程在执行insert操作时比较费时,所以线程池迅速被塞满。当其他有任务向线程池投放任务时,导致线程资源耗尽。正常情况下,32位操作系统程序有4G运行空间,用户和内核各占2个G,用户空间内,每个线程占用1m的栈空间,所以理论上最多支持2000多个线程。所以线程也是有上限的。这种方法在报警足够多到来时会有很大问题,所以我们进行了改进。主要改进有两个方式,第一、报警到来时不会立即将报警放入到线程池中执行操作,等数量足够或者时间超时后才会用一个线程进行批量处理。第二、报警插入数据库时,采用批量事务处理以提高速度。经过这两种优化方法,线程数量和处理速度明显快了很多,提高系统的稳定性。总之,通过缓存能够明显消除突然到来的大量报警带来的冲击,但是代价也是有的,这会导致我们的系统在处理报警时不会那么及时。不过对于系统崩溃的风险,这点时间是可以接收的。这个还需要长期观察。继续提高我们软件的稳定性。
其他的还有资源冲突的问题,以后详细说说,这里暂时不展开细说了。

你可能感兴趣的:(经验分享)