怎么才能提高服务器的并发处理能力?

什么是服务器?

不就是提供“付费”、“免费”服务的高档电脑嘛!

你提到服务?存储一个图片,读取一篇文字,观看一个动作片,计算一个账户存款,...

什么是并发?不如讲一讲什么是不并发。我有一台服务器,1核CPU,连接到互联网提供服务。在09:00时刻,突然有100个用户同时要看服务器的数据,服务器怎么办?

+-------+ 09:00

| |

| 服务器 |

| |

+-------+

|

|

----------------------------

互联网

----------------------------

| | | ...... |

客户1 客户2 客户3 客户100

服务器:

--> 读取客户1的请求, 验证客户身份, 把数据发送给你, 用时1秒 [ 客户2到100等待中 ]

--> 读取客户2的请求, 验证客户身份, 把数据发送给你, 用时1秒 [ 客户3到100等待中 ]

--> 读取客户3的请求, 验证客户身份, 把数据发送给你, 用时1秒 [ 客户4到100等待中 ]

........................................................................

--> 读取客户100的请求,验证客户身份, 把数据发送给你, 用时1秒

这就是“不并发”,即“迭代”,也就是“循环”的意思。

迭代 == 循环

既然来了100个客户,那么一个一个的处理,循环从客户1一直到客户100。处理完成客户1才去处理客户2,...。这样我们可以看出:

客户1从发出请求到收到响应,等待了1秒客户2从发出请求到收到响应,等待了2秒客户3从发出请求到收到响应,等待了3秒..................................客户100从发出请求到收到响应,等待了100秒

这就是“不并发”的问题,同时来100个客户,这些用户会排起长长的队伍,等待很长的时候,服务器才会去为他服务。客户可不喜欢这样的地方。

把服务器比喻成一个KFC,那么“不并发”就意味着只提供一个服务员,来了100个客户,当然要排个长长的队伍了。

那什么是高并发呢?所谓高并发指的是:在同时或极短时间内,有大量的请求到达服务端,每个请求都需要服务端耗费资源进行处理,并做出相应的反馈。

常用的高并发处理的思路与手段

从服务端视角看高并发

服务端处理请求需要耗费服务端的资源,比如能同时开启的进程数、能同时运行的线程数、网络连接数、cpu、I/O、内存等等,由于服务端资源是有限的,那么服务端能同时处理的请求也是有限的。高并发问题的本质就是:资源的有限性

高并发带来的问题

服务端的处理和响应会越来越慢,甚至会丢弃部分请求不予处理,更严重的会导致服务端崩溃。

高并发处理的基本思路

1)从客户端看

尽量减少请求数量,比如:依靠客户端自身的缓存或处理能力尽量减少对服务端资源的不必要耗费,比如:重复使用某些资源,如连接池客户端处理的基本原则就是:能不访问服务端就不要访问

2)从服务端看

增加资源供给,比如:更大的网络带宽,使用更高配置的服务器,使用高性能的Web服务器,使用高性能的数据库请求分流,比如:使用集群,分布式的系统架构应用优化,比如:使用更高效的编程语言,优化处理业务逻辑的算法,优化访问数据库的SQL

基本原则:分而治之,并提高单个请求的处理速度

怎么做才能提高服务器的并发处理能力?

1. 提高CPU并发计算能力

服务器之所以可以同时处理多个请求,在于操作系统通过多执行流体系设计使得多个任务可以轮流使用系统资源,这些资源包括CPU,内存以及I/O. 这里的I/O主要指磁盘I/O, 和网络I/O。

多进程 & 多线程

多执行流的一般实现便是进程,多进程的好处可以对CPU时间的轮流使用,对CPU计算和IO操作重叠利用。这里的IO主要是指磁盘IO和网络IO,相对CPU而言,它们慢的可怜。

而实际上,大多数进程的时间主要消耗在I/O操作上。现代计算机的DMA技术可以让CPU不参与I/O操作的全过程,比如进程通过系统调用,使得CPU向网卡或者磁盘等I/O设备发出指令,然后进程被挂起,释放出CPU资源,等待I/O设备完成工作后通过中断来通知进程重新就绪。对于单任务而言,CPU大部分时间空闲,这时候多进程的作用尤为重要。

多进程不仅能够提高CPU的并发度。其优越性还体现在独立的内存地址空间和生命周期所带来的稳定性和健壮性,其中一个进程崩溃不会影响到另一个进程。

但是进程也有如下缺点:

fork()系统调用开销很大: prefork进程间调度和上下文切换成本: 减少进程数量庞大的内存重复:共享内存IPC编程相对比较麻烦

减少进程切换

当硬件上下文频繁装入和移出时,所消耗的时间是非常可观的。可用Nmon工具监视服务器每秒的上下文切换次数。为了尽量减少上下文切换次数,最简单的做法就是减少进程数,尽量使用线程并配合其它I/O模型来设计并发策略。

还可以考虑使用进程绑定CPU技术,增加CPU缓存的命中率。若进程不断在各CPU上切换,这样旧的CPU缓存就会失效。

减少使用不必要的锁

服务器处理大量并发请求时,多个请求处理任务时存在一些资源抢占竞争,这时一般采用“锁”机制来控制资源的占用,当一个任务占用资源时,我们锁住资源,这时其它任务都在等待锁的释放,这个现象称为锁竞争。

通过锁竞争的本质,我们要意识到尽量减少并发请求对于共享资源的竞争。比如在允许情况下关闭服务器访问日志,这可以大大减少在锁等待时的延迟时间。要最大程度减少无辜的等待时间。

这里说下无锁编程,就是由内核完成这个锁机制,主要是使用原子操作替代锁来实现对共享资源的访问保护 ,使用原子操作时,在进行实际的写操作时,使用了lock指令,这样就可以阻止其他任务写这块内存,避免出现数据竞争现象。原子操作速度比锁快,一般要快一倍以上。

例如fwrite(), fopen(),其是使用append方式写文件,其原理就是使用了无锁编程,无锁编程的复杂度高,但是效率快,而且发生死锁概率低。

考虑进程优先级

进程调度器会动态调整运行队列中进程的优先级,通过top观察进程的PR值

考虑系统负载

可在任何时刻查看/proc/loadavg, top中的load average也可看出

考虑CPU使用率

除了用户空间和内核空间的CPU使用率以外,还要关注I/O wait,它是指CPU空闲并且等待I/O操作完成的时间比例(top中查看wa的值)。

2. 考虑减少内存分配和释放

服务器的工作过程中,需要大量的内存,使得内存的分配和释放工作尤为重要。可以通过改善数据结构和算法复制度来适当减少中间临时变量的内存分配及数据复制时间,而服务器本身也使用了各自的策略来提高效率。

例如Apache,在运行开始时一次申请大片的内存作为内存池,若随后需要时就在内存池中直接获取,不需要再次分配,避免了频繁的内存分配和释放引起的内存整理时间。

再如Nginx使用多线程来处理请求,使得多个线程之间可以共享内存资源,从而令它的内存总体使用量大大减少,另外,nginx分阶段的内存分配策略,按需分配,及时释放,使得内存使用量保持在很小的数量范围。

另外,还可以考虑共享内存。共享内存指在多处理器的计算机系统中,可以被不同中央处理器(CPU)访问的大容量内存,也可以由不同进程共享,是非常快的进程通信方式。

但是使用共享内存也有不好的地方,就是对于多机器时数据不好统一。

shell命令ipcs可用来显示系统下共享内存的状态,函数shmget可以创建或打开一块共享内存区,函数shmat将一个存在的共享内存段连接到本进程空间, 函数shmctl可以对共享内存段进行多种操作,函数shmdt函数分离该共享内存。

3. 考虑使用持久连接

持久连接也为长连接,它本身是TCP通信的一种普通方式,即在一次TCP连接中持续发送多分数据而不断开连接,与它相反的方式称为短连接,也就是建立连接后发送一份数据就断开,然后再次建立连接发送下一份数据, 周而复始。是否采用持久连接,完全取决于应用特点。

从性能角度看,建立TCP连接的操作本身是一项不小的开销,在允许的情况下,连接次数越少,越有利于性能的提升; 尤其对于密集型的图片或网页等小数据请求处理有明显的加速所用。

HTTP长连接需要浏览器和web服务器的共同协作,目前浏览器普遍支持长连接,表现在其发出的HTTP请求数据头中包含关于长连接的声明,如下: Connection: Keep-Alive,主流的web服务器都支持长连接,比如apache中,可以用KeepAlive off关闭长连接。

对于长连接的有效使用,还有关键一点在于长连接超时时间的设置,即长连接在什么时候关闭吗? Apache的默认设置为5s, 若这个时间设置过长,则可能导致资源无效占有,维持大量空闲进程,影响服务器性能。

4. 改进I/O 模型

I/O操作根据设备的不同分为很多类型,比如内存I/O, 网络I/O, 磁盘I/O. 对于网络I/O和磁盘I/O, 它们的速度要慢很多,尽管使用RAID磁盘阵列可通过并行磁盘磁盘来加快磁盘I/O速度,购买大连独享网络带宽以及使用高带宽网络适配器可以提高网络i/O的速度。

但这些I/O操作需要内核系统调用来完成,这些需要CPU来调度,这使得CPU不得不浪费宝贵的时间来等待慢速I/O操作。我们希望让CPU足够少的时间在i/O操作的调度上,如何让高速的CPU和慢速的I/O设备更好地协调工作,是现代计算机一直探讨的话题。各种I/O模型的本质区别在于CPU的参与方式。

1. DMA技术

I/O设备和内存之间的数据传输方式由DMA控制器完成。在DMA模式下,CPU只需向DMA下达命令,让DMA控制器来处理数据的传送,这样可以大大节省系统资源。

2. 异步I/O

异步I/O指主动请求数据后便可以继续处理其它任务,随后等待I/O操作的通知,这样进程在数据读写时不发生阻塞。

异步I/O是非阻塞的,当函数返回时,真正的I/O传输已经完成,这让CPU处理和I/O操作达到很好的重叠。

3. I/O多路复用

epoll服务器同时处理大量的文件描述符是必不可少的,若采用同步非阻塞I/O模型,若同时接收TCP连接的数据,就必须轮流对每个socket调用接收数据的方法,不管这些socket有没有可接收的数据,都要询问一次。

假如大部分socket并没有数据可以接收,那么进程便会浪费很多CPU时间用于检查这些socket有没有可以接收的数据。多路I/O就绪通知的出现,提供了对大量文件描述符就绪检查的高性能方案,它允许进程通过一种方法同时监视所有文件描述符,并可以快速获得所有就绪的文件描述符,然后只针对这些文件描述符进行数据访问。

epoll可以同时支持水平触发和边缘触发,理论上边缘触发性能更高,但是代码实现复杂,因为任何意外的丢失事件都会造成请求处理错误。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值