影响服务器性能的首要因素就是系统的硬件资源,比如CPU的个数、速度、内存大小等。不过由于硬件技术的飞速发展,现代服务器都不缺硬件资源。因此,从软件层面提升服务器的性能。服务器的“软环境”,一方面是指系统的软件资源,比如操作系统允许用户打开的最大文件描述符数量;另一方指的就是服务器程序本身,如何从编程的角度确保服务器性能。
1、池
既然服务器的硬件资源“充裕”,那么提高服务器性能的一个直接的方法就是,以空间换时间,即“浪费”服务器的硬件资源,以换取其运行效率。这就是池的概念。池是一种资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这成为静态资源分配。直接从池中获得的所需资源比动态分配资源速度快的多,因为分配系统资源的系统调用都是很耗时的。当服务器处理完一个客户连接后,可以把相关资源放回池中,无须执行系统调用是释放资源。从最终的效果来看,相当于服务器管理系统资源的应用层设施,它避免的服务器对内核的频繁访问。
资源分配策略:预先分配一定资源,此后如果发现资源不够用,就再动态分配一些并加入池中。
根据不同的资源类型,常见的池有:内存池,进程池,线程池和连接池。
内存池:通常用于socket的接收缓存和发送缓存。对于某些长度有限的客户请求,比如HTTP请求,预先分配一个足够大的接收缓存区。当客户端的长度超过接收缓存区的大小时,我们可以选择丢弃请求或动态扩大接收缓存区。
2、数据复制
高性能服务器应该避免不必要的数据复制。尤其是当数据复制发生在用户代码和内核之间的时候。如果内核可以直接处理从socket或文件读入的数据,则应用程序就没有必要将这些数据从内核缓冲区复制到应用程序的缓冲区中。这里所说的“直接处理”指的是应用程序不关心这些数据的内容,不需要对他们做任何分析。
此外,用户代码内部的数据复制也是应该避免的。例如:当两个工作进程之间需要传递大量的数据时,我们就应该烤炉使用共享内存来在它们之间直接共享这些数据,而不是使用管道或者消息队列来传递。
3、上下文切换
并发程序必须考虑上下文的切换的问题,即进程切换或线程切换导致的系统开销。即使是I/O密集型的服务器,也不应该使用过多的工作线程,否则线程间切换将占用大量的CPU时间,服务器真正用于业务处理逻辑CPU时间的比重就显得不足。因此,为每个客户端创建一个工作线程的服务器模型是不可取的。
并发程序需要考虑的另外一个问题就是共享资源的加锁保护。锁通常被任务是导致任务是服务器效率低下一个因素,因为由它引入的代码不仅不处理任何业务逻辑,而且需要访问内核资源。因此,服务器如果有更好的解决方案,就应该避免使用锁。如果服务器必须使用锁,则可以考虑减小锁的粒度,比如使用读写锁。当所有工作线程都只读取一块共享内存的内容时,读写锁并不会增加系统额外的开销、只有当其中一个工作线程需要写这块内存时,系统才需要锁住这块内存。