系统性能主要瓶颈在I/O,包括数据库,socket,网络通信,文件等,例如频繁查询数据库并返回大量结果集,频繁操作大文件等,这些昂贵的操作会占用大量的CPU时间。实际上线环境下,存在多用户并发、大数据量的情况下就会暴露出严重的问题。所以性能设计时一定要考虑到I/O,同步,并发,资源争用,以及大数据量等因素。通常,I/O操作、网络响应、差的算法、数据库、以及其他的低效的资源使用都会导致低劣的性能。
具体可用的设计策略有:
1 缓存以及缓存层(caching layer)
在数据层和应用层之间增加数据缓存层,提供全局数据服务。可以大大减少数据库往返次数。与读取数据库和读取大文件(如XML文件)比,读取内存的速度无疑要快的多。所以对经常要访问的数据进行缓存是非常好的实践方法。因为现在系统往往内存很大,可以充分利用大内存,而共享内存更能实现数据并发访问。
2多线程(multi-threading)
现在基本上大部分软件实现多线程或多进程,多线程对单CPU系统还只是顺序利用CPU时间和改善用户体验,多CPU系统才是真正的并行。要注意的是多线程不要争抢访问同一资源而导致部分串行操作,要做到真正的并行操作多线程并不容易。另外,在多线程间同步一个庞大的资源,过多创建线程又没有实现线程池也会导致系统性能下降。
3 负载平衡(load balancing)
物理上增加地位对等的集群服务器(Cluster),通过负载分配算法分配相应服务器来相应客户端请求。很多系统支持负载均衡,Windows server2003 IIS就支持负载均衡服务,其他如WebLogic, WebSphere也有集群版本支持负载均衡。当然你也可以自己实现负载分配算法。
4数据库优化(database optimization)
如果应用程序使用了数据库,可以采取许多步骤来消除访问和写入数据时的瓶颈:
1)标识潜在的索引,但不要创建过多的索引。
2)如果使用 SQL Server,则使用 SQL Server 的事件探查器和索引优化向导。
3)监视处理器的使用;理想范围是:75-80% 处理器时间。
4)使用查询分析器分析查询计划以优化查询。
5)使用存储过程优化性能。
6)标准化写入的大量数据 —写入较少的数据。
7)取消标准化读取的大量数据 —读取较少的数据。
5文件系统优化
有时候系统性能不好,但当你关闭写log的功能,性能一下子提高很多。因为频繁的打开关闭大log文件时I/O开销非常大,同样记录log到数据库也一样。所以,release版尽量减少写log,或干脆移到裸设备上。
频繁打开关闭文件对系统性能下降程度是惊人的,可以通过一些变通办法来减少文件的频繁操作。
例如,原来的缓存持久化实现是保存在XML文件,每次要获得一个配置项,都打开XML文件,通过XPath拿到这个配置项的值,这样效率不高,而且容易把这个XML文件lock住;改进的方法是:通过比较XML文件的修改时间(System.IO.File.GetLastWriteTime)判断是否要再次打开文件,大大提高了效率;另一个可以改进的方法是:启动时读取所有配置到一个静态的HashTable,每次要获得一个配置项都从内存HashTable获取,在最后或适当的时候持久化到XML。
6代码性能设计
在编程实现上,代码性能设计也很重要,一些昂贵的操作会占用大量的资源和CPU时间。例如,字符串相加没用StringBuilder, 频繁创建对象,差劲的排序或递归算法,过多的装箱拆箱,过多的使用反射(Reflection),频繁new HashTable或大的数组,用异常(Catch Exception)用做正常的逻辑,使用复杂的正则表达式,等等。具体可以参考《Effective C++》《Effective C#》等书籍。
6语言的选择
另外,语言选择也很重要。比如相对于Java, C#, C++, 大多数OLTP系统用C语言效率高的多,因为在所有的高级程序设计语言中,C程序设计语言的运行效率是公认的。再比如我们熟悉的一些框架,框架本身是C#或是Java的,但其核心独立模块是C++封装的,这样可以达到最佳的性能。所以对于一些特定的业务需求目标和数据的具体情况,对于核心的模块或算法,可以用特定的语言来实现以获得更好的效率。
比如应用层和数据库的API,在.Net中就有就有DataReader、DataSet和IList等的选择以及转换等,这个根据具体情况而定;还有就是大家常采用的数据的格式化和压缩,以及采用分页,减少传输的数据量;是否可以把一部分处理逻辑放在客户端呢,减少服务端的工作量。界面端也是有很多针对性能优化的考虑,例如绘图,控件重绘都是非常耗资源的,各控件的数据加载和数据绑定性能也各不相同,尽量采用惰性加载,异步加载;初始化和启动速度等都是需要考虑和优化的。