服务器大并发的思考

1.不要让内核执行所有繁重的任务。将数据包处理,内存管理,处理器调度等任务从内核转移到应用程序高效地完成。让Linux内核只处理控制层,数据层完全交给应用程序来处理。
2.用事件驱动服务器(如Nginx和Node)代替线程服务器(Apache)
3.实现数据包可扩展——编写自己的个性化驱动来绕过堆栈

数据包的问题是它们需经Unix内核的处理。网络堆栈复杂缓慢,数据包最好直接到达应用程序,而非经过操作系统处理之后。
做到这一点的方法是编写自己的驱动程序。所有驱动程序将数据包直接发送到应用程序,而不是通过堆栈。你可以找到这种驱动程序:PF_RING,NETMAP,Intel DPDK(数据层开发套件)。Intel不是开源的,但有很多相关的技术支持。
速度有多快?Intel的基准是在一个相当轻量级的服务器上,每秒处理8000万个数据包(每个数据包200个时钟周期)。这也是通过用户模式。将数据包向上传递,使用用户模式,处理完毕后再返回。Linux每秒处理的数据包个数不超过百万个,将UDP数据包提高到用户模式,再次出去。客户驱动程序和Linux的性能比是80:1。
对于每秒1000万个数据包的目标,如果200个时钟周期被用来获取数据包,将留下1400个时钟周期实现类似DNS / IDS的功能。
通过PF_RING得到的是原始数据包,所以你必须做你的TCP堆栈。人们所做的是用户模式栈。Intel有现成的可扩展TCP堆栈
4.多核的可扩展性

多核可扩展性不同于多线程可扩展性。

多线程
每个CPU内核中不止一个线程
用锁来协调线程(通过系统调用)
每个线程有不同的任务
多核
每个CPU内核中只有一个线程
当两个线程/内核访问同一个数据时,不能停下来互相等待
同一个任务的不同线程
要解决的问题是怎样将一个应用程序分布到多个内核中去

解决方案:
在每个核心中保存数据结构,然后聚合的对数据进行读取。
原子性。CPU支持可以通过C语言调用的指令,保证原子性,避免冲突发生。开销很大,所以不要处处使用。
无锁的数据结构。线程无需等待即可访问,在不同的架构下都是复杂的工作,请不要自己做。
线程模型,即流水线与工作线程模型。这不只是同步的问题,而是你的线程如何架构。
处理器关联。告诉操作系统优先使用前两个内核,然后设置线程运行在哪一个内核上,你也可以通过中断到达这个目的。所以,CPU由你来控制而不是Linux。
5.内存的可扩展性

如果你有20G的RAM,假设每次连接占用2K的内存,如果你还有20M的三级缓存,缓存中会没有数据。数据转移到主存中处理花费300个时钟周期,此时CPU没有做任何事情。
每个数据包要有1400个时钟周期(DNS / IDS的功能)和200个时钟周期(获取数据包)的开销,每个数据包我们只有4个高速缓存缺失,这是一个问题。
联合定位数据
不要通过指针在满内存乱放数据。每次你跟踪一个指针,都会是一个高速缓存缺失:[hash pointer] -> [Task Control Block] -> [Socket] -> [App],这是四个高速缓存缺失。
保持所有的数据在一个内存块:[TCB |socket| APP]。给所有块预分配内存,将高速缓存缺失从4减少到1。
分页
32GB的数据需占用64MB的分页表,不适合都存储在高速缓存。所以存在两个高速缓存缺失——分页表和它所指向的数据。这是开发可扩展的软件不能忽略的细节。
解决方案:压缩数据,使用有很多内存访问的高速缓存架构,而不是二叉搜索树
NUMA架构加倍了主存访问时间。内存可能不在本地socket,而是另一个socket上。
内存池
启动时立即预先分配所有的内存
在对象,线程和socket的基础上进行分配。
超线程
每个网络处理器最多可以运行4个线程,英特尔只能运行2个。
在适当的情况下,我们还需要掩盖延时,比如内存访问中一个线程在等待另一个全速的线程。
大内存页
减小页表规模。从一开始就预留内存,让你的应用程序管理内存。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值