第3章 服务器并发处理能力
3.1 吞吐率
- 吞吐率:Web服务器单位时间内处理的请求数
- 最大吞吐率:单位时间内服务器能够处理的最大请求数
- 压力测试:模拟大量并发用户持续发送HTTP请求,统计测试持续的总时间,据此计算吞吐率。(一般会简化模型,对有代表性的特定请求进行压力测试)
3.1.1 压力测试的前提条件
- 并发用户数:某一时刻同时向服务器发送请求的用户总数。
- 总请求数
- 请求资源描述
3.1.2 请求等待时间
- 用户平均请求等待时间:一定并发用户数下,对于单个用户的服务质量
- 服务器平均请求处理时间:吞吐率的倒数
- Web服务器使用多个执行流并发处理请求(交错使用CPU时间片),单个用户的请求等待时间会拉长,但服务器平均请求时间可能减少。
3.1.3 来一次压力测试
- 压力测试软件:ab,LoadRunner,Jmeter
ab测试:
ab -n1000 -c10 http://xxx.com/test.html #-n1000 表示总请求数1000 #-c10 表示并发用户数10
请求结果
Concurrency Level: 10 Time taken for tests: 7.616 seconds Complete requests: 1000 Failed requests: 0 Non-2xx responses: 1000 Total transferred: 374000 bytes HTML transferred: 178000 bytes Requests per second: 131.30 [#/sec] (mean) Time per request: 76.161 [ms] (mean) Time per request: 7.616 [ms] (mean, across all concurrent requests) Transfer rate: 47.96 [Kbytes/sec] received
吞吐率
Requests per second = Complete requests / Time taken for tests
用户平均请求等待时间Time per request = Time per request / (Complete requests / Concurrency Level)
服务器平均请求处理时间Time per request(across all concurrent requests) = Time taken for tests / Complete requests
3.1.4 继续压力测试
- 并发策略的设计,就是在服务器同时处理较多请求的时候,合理协调并充分利用CPU计算和I/O操作,使其在较大并发用户的情况下提供较高吞吐率。
3.2 CPU并发计算
- 进程(fork):由内核调度,担当分配资源的实体,通过进程描述符与数据关联
- 子进程:将父进程所以数据复制到自己的地址空间,继承父进程所有上下文信息
- 轻量级进程(clone):允许共享地址空间,文件,支持数据共享
- 线程:pthread 在用户态完成多线程管理;LinuxThreads 将线程和轻量级进程一对一关联,由内核进程调度器管理
- 进程调度器(Scheduler):维护所有可运行进程队列(Run Quere),和一个包括所有休眠进程,僵尸进程的列表
进程优先级:通过top观察
PR 优先级属性:进程调度器分配给进程的时间片长度,单位为时钟个数,Linux一般为10ms NI 优先级动态调整值
系统负载:运行队列中任何时刻至少存在一个进程,那就是正在运行的进程。
cat /proc/loadavg 0.00 0.01 0.00 1/382 4154 前3个数 最近1,5,15分钟的系统负载 // 1 此时运行队列中的进程数 // 382 进程总数 // 4154 最后创建的进程ID
- 进程切换:挂起正在运行的进程,恢复以前挂起的进程,称为进程切换(上下文切换)
- 进程挂起:将进程在CPU寄存器中的数据拿出来暂存在内核态堆栈中
- Nmon监控:ContextSwitch 上下文每秒切换次数
查看某时刻httpd进程数
ps afx | grep httpd | wc -l
- 总结:如果希望服务器支持较大并发数,就要尽量减少上下文切换次数,最简单的做法就是减少进程数,使用线程并配合其他I/O模型来设计并发策略
- IOWait:CPU空闲并且等待I/O操作完成的时间比例(通过Nmon得到CPU监控数据)
- 锁竞争:当一个任务占用锁住资源的时候,其他任务都在等待锁的释放。要尽量减少并发请求对于共享资源的占用。
3.3 系统调用
- 系统调用(英语:system call),又称为系统呼叫,指运行在用户空间的程序向操作系统内核请求需要更高权限运行的服务。
- 用户态和内核态是Linux进程的两种运行级别,进程可以在两种模式间切换。
- Linux系统上,应用代码通过glibc库封装的函数,间接使用系统调用。
- 系统调用涉及进程从用户态到内核态的切换,导致一定的内存空间交换,所以Web服务器优化要减少不必要的系统调用。
- 使用strace跟踪子进程
3.4 内存分配
- 频发的内存分配和释放会引发一定时间的内存整理,影响性能
- Apache是多进程模型,使用内存池管理内存,开始运行时一次性申请大片内存作为内存池
- Nginx是单进程模型,使用多线程处理请求,线程间可以共享内存资源
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。