博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
高性能服务器本质论
阅读量:5302 次
发布时间:2019-06-14

本文共 2416 字,大约阅读时间需要 8 分钟。

一 服务器分类

从软件性能角度,高性能服务器分:cpu密集型服务器/IO密集型服务器
(1)CPU密集型:该类服务器没有对io的访问/没有同步点,性能瓶颈在于对cpu的充分利用
典型的如转发服务器/代理服务器/协议转换类服务器/分布式总线服务器等。
(2)IO密集型:该类服务器存在对cache/db/硬盘等的同步访问,或者对fcgi/其他服务器等的同步访问
简单说有同步访问点的均归属此类服务器。当前硬件基础下,有同步操作的服务器,性能瓶颈均在同步点的返回快慢上,而非cpu。
二 网络层机制
对 上述两类服务器,均需要同样高效的网络层机制。当前高效的网络层也就是大家熟知的iocp/epoll/kqueue/port/dev.poll等,在 各个os下使用宿主os推荐的高效网络层机制,任何通过其他机制绕过这些机制的做法都不可能达到最好性能。这里推荐下boost.asio,文档齐全,示 例丰富,学习曲线平缓。
三 CPU密集型服务器设计
(1)单进程单线程是改类服务器的本质特征。
整个进程只存在一个线程,所有代码均运行在同一个线程中,均顺序执行,任何地方不需要加锁。由于网络线程的存在,实际上该类程序的唯一线程就是网络线程,以linux为例,就是epoll线程。
在多核情况下,fork和cpu个数相同的进程数并且如果可能使用sched_setaffinity类函数将进程和cpu绑定。以充分利用多核性能。
该类服务器的代表:tuxedo/nginx.
(2)单进程多线程,但多线程均完成同样的功能,彼此之间互不依赖/互不影响 ,这是该类服务器的变体。
单 进程单线程无疑是该类服务器最理想最完美的实现。但有时候为了简化部署,简化业务上报,业务自检,统一日志,尤其是统计类日志/配置动态生效等附加功能考 虑,不得已牺牲少许性能而将上述“单进程单线程,fork多个充分利用多核”方案改造为“独立多线程充分利用多核”方案。
该方案中,多线程中的各个线程仍然是顺序执行,任何地方不需要加锁,均为独立的网络线程。
相对方案(1), 该方案编程更复杂,而linux下线程调度又不如进程高效,整体看为方便性牺牲了少许性能。
该类服务器的代表:我们的协议转换网关/分布式总线服务器等。
(3)高效算法
优化耗时较多算法/挑选合适容器,完成固定任务,尽量减少cpu的运算量。
(4)错误设计:区分网络线程/业务线程,将业务线程根据业务特点划分各个线程阶段。
对 cpu密集型的服务器来说,关键在于充分利用cpu,尽量减少无用代码的执行。引如中间处理线程,意味着引入锁切换/内存复制/更多无效代码,不可否认, 在已有协议栈情况下,根据业务特点化分线程可以简化编程。单纯的单一线程意味着更复杂的编码,尤其是涉及到更多中间状态时。
在该场景下,有位牛人,对线程的点评:“线程是给那些不能将程序执行序转换成状态机的笨人用的” 这句话真是再合适不过了。
四 IO密集型服务器设计
(1)网络层多线程,中间线程按照业务特点设定,同步点操作使用多线程
同 步点使用多线程是该类服务器的本质特征。在同步操作的返回时间不能由本服务器控制的前提下,本服务器所能做的也就只能是加多线程数,提供同步并发数。线程 数的最优配置取决于网络层入口并发数以及同步操作返回的时间。简单划分可以网络线程数=cpu个数/2.同步点线程数还取决于同步操作的代价,若为廉价的 cache操作,则可适当增多,若为昂贵的db操作,则要根据可以分配的连接数决定。
(2)减少人为产生的同步点
尽量减少访问其他系统使用同步接口。
(3)优化同步点
根据同步操作的特点优化: 异步/增大缓存/批量等。
五 内存操作/锁机制/内核态用户态切换/日志操作
(1)内存操作
内存申请:减少内存动态分配,推荐tcmalloc
内存复制:CPU密集型,必须的内存复制:(a)网络读:处从内核态复制到用户态,仅1次 (b)网络写:异步内存复制/用户态到内核态 ,仅2次
                    IO密集型,内存复制非关键点。
(2)锁机制 CPU密集型:尽量无锁. IO密集型: 非关键点
(3)内核态用户态切换
两类服务器均相同,尽量减少内核态/用户态互相切换:每次调用系统调用尽可能读取更多字符/仅可能减少不必要的系统调用(去除不必要的调用/通过缓存机制减少调用次数)。
(4)日志操作 略

六 进程vs线程vs协程

进程和线程(略)
协程:和进程/线程这种cpu调度单元不同,它更多是线程内对象之间一种调度理念的优化。协程对象有自己的堆栈,可以通过直接跳转直接转换执行点,减少了内存寻址操作。它特别适合用来优化线程内的某些基础组件,包括:状态机/调停者模式(或者线程内队列)。

在CPU密集型服务器的设计中,说道“线程是给那些不能将程序执行序转换成状态机的笨人用的”,而有了协程,我们有了一种新的简化编程的方法。将协程用于网络层,可以手动实现类似select的功能,用于多对象参与的复杂中间状态,可以简化编程。

但从整体性能角度看,协程则是鸡肋的存在,从几年前出现boost.Coroutine,到现在该项目停止开发,boost引入更多其他方案asio/mpl/statechart,协程一路蹒跚。
七 总结
在当前硬件体系架构下,服务器性能的关键仍然是传统的cpu/io/memory.
cpu密集型的服务器,需要最大限度充分利用所有cpu,以及尽量少的进行内存申请/内存复制。
IO密集型服务器,需要最大限度提高io能力,为达到该目的,可以在非同步线程牺牲对cpu的利用率/牺牲对memory的高效使用,一切为提高io并发能力服务。
八  后记
特别感谢张杰同学代替我编译探测程序代码,让我有时间码点文字。

转载于:https://www.cnblogs.com/lchb/articles/3533618.html

你可能感兴趣的文章
ubuntu重装mysql
查看>>
JS 学习笔记
查看>>
English trip -- VC(情景课)1 C What's your name?(review)
查看>>
redirect的错误用法asp.net怎么使用自定义错误
查看>>
在MyEclipse下统计工程的代码(package、行数、类个数)
查看>>
Erlcron分析学习
查看>>
idea 快捷键
查看>>
SimpleDateFormate的使用
查看>>
菜鸟运维笔记:Windows上用Xshell管理你的云主机
查看>>
JavaScript中的this
查看>>
Activity生命周期
查看>>
jsp
查看>>
OpenNI / NITE的Stable版更新
查看>>
03 基本数据结构 - 栈
查看>>
Hyper-V虚拟机上安装一个图形界面的Linux系统
查看>>
微信小程序之随笔
查看>>
每秒处理10万高并发订单的乐视集团支付系统架构分享
查看>>
Lua_02
查看>>
ios蓝牙详解
查看>>
安装MySQL5.7.18遇到的坑
查看>>