提高服务器性能的建议

提高服务器性能的建议

既然服务器的硬件资源”充裕“,那么提高服务器性能的一个很直接的方法就是以空间换时间,即”浪费“服务器的硬件资源,以换取其运行效率。这就是池的概念。池是一组资源的集合,这组资源在服务器启动之初就被完全创建好并初始化,这称为静态资源分配。当服务器进入正式运行阶段,即开始处理客户请求的时候,如果它需要相关的资源,就可以直接从池中获取,无需动态分配。很显然,直接从池中取得所需资源比动态分配资源的速度要快得多,因为分配系统资源的系统调用都是很耗时的。当服务器处理完一个客户连接后,可以把相关的资源放回池中,无须执行系统调用来释放资源。从最终的效果来看,池相当于服务器管理系统资源的应用层设施,它避免了服务器对内核的频繁访问。

不过,既然池中的资源是预先静态分配的,我们就无法预期应该分配多少资源。最简单的解决方法就是分配”足够多“的资源,即针对每个可能的客户链接都分配必要的资源。这通常会导致资源的浪费。另一种解决方案就是预先分配一定的资源,然后如果发现资源不够用,就再动态分配一些并加入池中。

池可分为多种,常见的有内存池,进程池,线程池和连接池

内存池常用于socket的接收缓存和发送缓存。对于某些长度有限的客户请求,比如HTTP请求,预先分配一个大小足够的接收缓存区是很合理的。当客户请求的长度超过接收缓冲区的大小时,我们可以选择丢弃请求或者动态扩大接受缓冲区。

进程池和线程池都是并发编程的技术。当我们需要一个工作进程或工作线程来处理到来的客户请求时,我们可以直接从进程池或线程池中取得一个执行实体,而无须动态地调用forkpthread_create等函数来创建进程和线程。

连接池通常用于服务器或服务器机群的内部永久连接。逻辑单元每次需要访问数据库的时候,就像数据库程序发起连接,而访问完毕后释放连接。很显然,这种做法效率太低。一种解决方案就是使用连接池。连接池是服务器预先和数据库程序建立的一组连接的集合。当某个逻辑单元需要访问数据库时,它可以直接从连接池中取得一个连接的实体并使用,待完成数据库的访问之后,逻辑单元再将连接返还给连接池。

数据复制

高性能服务器应该避免不必要的数据复制,尤其是当数据复制发生在用户代码和内核之间的时候。如果内核可以直接处理从socket或者文件读入的数据,则应用程序就没必要将这些数据从内核缓冲区复制到应用程序缓冲区中。这里说的”直接处理“指的是应用程序不关心这些数据的内容,不需要对它们做任何分析。比如ftp服务器,当客户请求一个文件时,服务器只需要检测目标文件是否存在,以及客户是否有读取它的权限,而绝对不会关心文件的具体内容。这样的话,ftp服务器就无须把目标文件的内容完整地读入到应用程序缓冲区中并调用send函数来发送,而是使用”零拷贝“函数sendfile来直接将其发送到客户端。

用户代码内部(不访问内核)的数据复制也应该避免。举例来说,当两个工作进程之间要传递大量的数据时,应该考虑使用共享内存来在它们之间直接共享这些数据,而不是使用管道或者消息队列来传递

上下文切换和锁

并发程序必须考虑上下文切换的问题,即进程切换或线程切换导致的系统开销。即使是I/O密集型的服务器,也不应该使用过多的工作线程,否则线程间的切换将占用大量的CPU时间,服务器真正用于处理业务逻辑的CPU时间的比重就显得不足了。因此,为每个客户连接都创建一个工作线程的服务器模型是不可取的。半同步/半异步模式是一种比较合理的解决方案,它允许一个线程同时处理多个客户链接。此外,多线程服务器的一个优点是不同的线程可以同时运行在不同的CPU上。当线程的数量不大于CPU的数目时,上下文的切换就不是问题了。

并发程序需要考虑的另一个问题是共享资源的加锁保护。锁通常被认为是导致服务器效率低下的一个因素,因为由它引入的代码不仅不处理任何业务逻辑,而且需要访问内核资源。因此,服务器如果有更好的解决方案,就应该避免使用锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值