千万级并发实现的秘密:内核不是解决方案,而是问题所在!

既然我们已经解决了 C10K并发连接问题,应该如何提高水平支持千万级并发连接?你可能会说不可能。不,现在系统已经在用你可能不熟悉甚至激进的方式支持千万级别的并发连接。

要知道它是如何做到的,我们首先要了解Errata Security的CEO Errata Security,以及他在Shmoocon 2013大会上的“无稽之谈”—— C10M Defending The Internet At Scale。

Robert用一种我以前从未听说的方式来很巧妙地解释了这个问题。他首先介绍了一点有关Unix的历史,Unix的设计初衷并不是一般的服务器操作系统,而是电话网络的控制系统。由于是实际传送数据的电话网络,所以在控制层和数据层之间有明确的界限。问题是我们现在根本不应该使用Unix服务器作为数据层的一部分。正如设计只运行一个应用程序的服务器内核,肯定和设计多用户的服务器内核是不同的。

也就是他所说的——关键要理解内核不是解决办法,内核是问题所在。

这意味着:

不要让内核执行所有繁重的任务。将数据包处理,内存管理,处理器调度等任务从内核转移到应用程序高效地完成。让Linux只处理控制层,数据层完全交给应用程序来处理。

最终就是要设计这样一个系统,该系统可以处理千万级别的并发连接,它在200个时钟周期内处理数据包,在14万个时钟周期内处理应用程序逻辑。由于一次主存储器访问就要花费300个时钟周期,所以这是最大限度的减少代码和缓存丢失的关键。

面向数据层的系统可以每秒处理1千万个数据包,面向控制层的系统,每秒只能处理1百万个数据包。

这似乎很极端,请记住一句老话:可扩展性是专业化的。为了做好一些事情,你不能把性能问题外包给操作系统来解决,你必须自己做。
现在,让我们学习Robert如何创建一个能够处理千万级别并发连接的系统。

C10K问题——最近十年

十年前,工程师处理C10K可扩展性问题时,尽量避免服务器处理超过1万个的并发连接。通过改进操作系统内核以及用事件驱动服务器(如Nginx和Node)代替线程服务器(Apache),这个问题已经被解决。人们用十年的时间从Apache转移到可扩展服务器,在近几年,可扩展服务器的采用率增长得更快了。

Apache的问题

Apache的问题在于服务器的性能会随着连接数的增多而变差
关键点:性能和可扩展性并不是一回事。当人们谈论规模时,他们往往是在谈论性能,但是规模和性能是不同的,比如Apache。持续几秒的短期连接,比如快速事务,如果每秒处理1000个事务,只有约1000个并发连接到服务器。事务延长到10秒,要维持每秒1000个事务,必须打开1万个并发连接。这种情况下:尽管你不顾DoS攻击,Apache也会性能陡降;同时
大量的下载操作也会使Apache崩溃。如果每秒处理的连接从5千增加到1万,你会怎么做?比方说,你升级硬件并且提高处理器速度到原来的2倍。发生了什么?你得到两倍的性能,但你没有得到两倍的处理规模。每秒处理的连接可能只达到了6000。你继续提高速度,情况也没有
改善。甚至16倍的性能时,仍然不能处理1万个并发连接。所以说性能和可扩展性是不一样的。问题在于Apache会创建一个CGI进程,然后关闭,这个步骤并没有扩展。为什么呢?内核使用的O(N^2)算法使服务器无法处理1万个并发连接。内核中的两个基本问题:连接数=线程数/进程数。当一个数据包进来,内核会遍历其所有进程以决定由哪个进程来处理这个数据包。连接数=选择数/轮询次数(单线程)。同样的可扩展性问题,每个包都要走一遭列表上所有的socket。解决方法:改进内核使其在常数时间内查找。使线程切换时间与线程数量无关。使用一个新的可扩展epoll()/IOCompletionPort常数时间去做socket查询。因为线程调度并没有得到扩展,所以服务器大规模对socket使用epoll方法,这样就导致需要使用异步编程模式,而这些编程模式正是Nginx和Node类型服务器具有的;所以当从Apache迁移到Nginx和Node类型服务器时,即使在一个配置较低的服务器上增加连接数,性能也不会突降;所以在10K连接时,一台笔记本电脑的速度甚至超过了16核的服务器。

C10M问题——未来十年

不远的将来,服务器将要处理数百万的并发连接。IPv6协议下,每个服务器的潜在连接数都是数以百万级的,所以处理规模需要升级。

如IDS / IPS这类应用程序需要支持这种规模,因为它们连接到一个服务器骨干网。其他例子:DNS根服务器,TOR节点,互联网Nmap,视频流,银行,Carrier NAT,VoIP PBX,负载均衡器,网页缓存,防火墙,电子邮件接收,垃圾邮件过滤。通常人们将互联网规模问题归根于应用程序而不是服务器,因为他们卖的是硬件+软件。你买设备,并将其应用到你的数据中心。这些设备可能包含一块Intel主板或网络处理器以及用来加密和检测数据包的专用芯片等。截至2013年2月,40Gpbs,32芯,256G RAM 的X86处理器在Newegg网站上的报价是5000美元。该服务器可以处理1万个以上的并发连接,如果它们不能,那是因为你选择了错误的软件,而不是底层硬件的问题。这个硬件可以很容易地扩展到1千万个并发连接。

10M的并发连接挑战意味着什么:

1千万的并发连接数 100万个连接/秒——每个连接以这个速率持续约10秒 10GB/秒的连接——快速连接到互联网。 1千万个数据包/秒——据估计目前的服务器每秒处理50K的数据包,以后会更多。过去服务器每秒可以处理100K的中断,并且每一个数据包都产生中断。 10微秒的延迟——可扩展服务器也许可以处理这个规模,但延迟可能会飙升。 10微秒的抖动——限制最大延迟 并发10核技术——软件应支持更多核的服务器。通常情况下,软件能
轻松扩展到四核。服务器可以扩展到更多核,因此需要重写软件,以支持更多核的服务器。

我们所学的是Unix而不是网络编程

很多程序员通过W. Richard Stevens所著的《Unix网络编程》学习网络编程技术。问题是,这本书是关于Unix的,而不只是网络编程。它告诉你,让Unix做所有繁重的工作,你只需要在Unix的上层写一个小服务器。但内核规模不够,解决的办法是尽可能将业务移动到内核之外,并且自己处理所有繁重的业务。这方面有影响的一个例子是Apache每个连接线程的模型。这意味着线程调度程序根据将要到来的数据确定接下来调用哪一个read()函数,也就是把线程调度系统当作数据包调度系统来用。(我真的很喜欢这一点,从来没有想过这样的说法)。Nginx宣称,它不把线程调度当作数据包调度程序,而是自己进行数据包调度。使用select找到socket,我们知道数据来了,就可以立即读取并处理数据,数据也不会堵塞。经验:让Unix处理网络堆栈,但之后的业务由你来处理。

怎样编写规模较大的软件?

如何改变你的软件,使其规模化?许多只提升硬件性能去支撑项目扩展的经验都是错误的,我们需要知道性能的实际情况。

要达到到更高的水平,需要解决的问题如下:

数据包的可扩展性 多核的可扩展性 内存的可扩展性

实现数据包可扩展——编写自己的个性化驱动来绕过堆栈

数据包的问题是它们需经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内核中只有一个线程当两个线程/内核访问同一个数据时,不能停下来互相等待同一个任务的不同线程要解决的问题是怎样将一个应用程序分布到多个内核中去Unix中的锁在内核实现。4内核使用锁的情况是大多数软件开始等待其他线程解锁。因此,增加内核所获得的收益远远低于等待中的性能损耗。我们需要这样一个架构,它更像高速公路而不是红绿灯控制的十字路口,无需等待,每个人都以自己的节奏行进,尽可能节省开销。解决方案:在每个核心中保存数据结构,然后聚合的对数据进行读取。原子性。CPU支持可以通过C语言调用的指令,保证原子性,避免冲突发生。开销很大,所以不要处处使用。无锁的数据结构。线程无需等待即可访问,在不同的架构下都是复杂的工作,请不要自己做。线程模型,即流水线与工作线程模型。这不只是同步的问题,而是你的线程如何架构。处理器关联。告诉操作系统优先使用前两个内核,然后设置线程运行在哪一个内核上,你也可以通过中断到达这个目的。所以,CPU由你来控制而不是Linux。

内存的可扩展性

如果你有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个。在适当的情况下,我们还需要掩盖延时,比如内存访问中一个线程在等待另一个全速的线程。大内存页减小页表规模。从一开始就预留内存,让你的应用程序管理内存。

总结

网卡问题:通过内核工作效率不高解决方案:使用自己的驱动程序并管理它们,使适配器远离操作系统。CPU问题:使用传统的内核方法来协调你的应用程序是行不通的。解决方案:Linux管理前两个CPU,你的应用程序管理其余的CPU。中断只发生在你允许的CPU上。内存问题:内存需要特别关注,以求高效。解决方案:在系统启动时就分配大部分内存给你管理的大内存页

控制层交给Linux,应用程序管理数据。应用程序与内核之间没有交互,没有线程调度,没有系统调用,没有中断,什么都没有。
然而,你有的是在Linux上运行的代码,你可以正常调试,这不是某种怪异的硬件系统,需要特定的工程师。你需要定制的硬件在数据层提升性能,但是必须是在你熟悉的编程和开发环境上进行。

时间: 2024-10-30 09:01:12

千万级并发实现的秘密:内核不是解决方案,而是问题所在!的相关文章

HAProxy千万级并发问题解决方案

HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理.HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接.并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上. 1.问题描述 RMI上线后,现网的接口总是报告异常. 2.问题分析 通过对RMI源码的理解,这个是在RMI客户端那边没有可用的连接时,需要创建一个新的连接,但是连接失败. 网络问题一般抓包可以定位,于是通过抓包发现失败的连接有个共同的现

TableStore发布Timeline Lib:轻松构建千万级IM和Feed流系统

场景 移动互联网时代,微信和微博已经成为这个时代的两大支柱类社交应用.这两类应用,其中一个是IM产品,一个是Feed流产品,微信的朋友圈也属于Feed流.如果再细心去发现,会发现基本所有移动App都有Feed流的功能:消息广场.个人关注.通知.新闻聚合和图片分享等等.各种各样的Feed流产品占据了我们生活的方方面面. 现状 IM和Feed流功能已经基本成为所有App标配,如何开发一个IM或者Feed流功能是很多架构师.工程师要面临的问题.虽然是一个常见功能,但仍然是一个巨大的挑战,要考虑的因素非

千万级-高并发WEB设计问题,来自一个面试题

问题描述 高并发WEB设计问题,来自一个面试题 这是一个面试题,困扰我好长时间了. 有个网站首页,需要满足千万级小数据量用户访问,首页上包含如下几部分: 1 统计部分,全站统计,与具体用户无关,与已存储的数据有关 2 静态页面部分 3 个人统计部分,与当前登录用户用惯,与已存储的数据有关,个人统计数据很少 4 数据部分,与具体内容无关,与已存储的数据有关.数据很少 要求: 1 满足千万级用户访问 2 前端可以负载,可以集群,可以异步 3 后端存储可以是DB,可以是内存,也可以是其他 4 技术 架

新浪微博千万级规模高性能、高并发的网络架构经验分享

[本文转载自新浪微博千万级规模高性能.高并发的网络架构经验分享] 架构以及我理解中架构的本质 在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上要重视它,战术上又要藐视它. 先举个例子感受一下千万级到底是什么数量级?现在很流行的优步(Uber),从媒体公布的信息看,它每天接单量平均在百万左右, 假如每天有10个小时的服务时间,平均QPS只有30左右.对于一个后台服务器,单机的平均QPS可以到达800-1000,单独看写

千万级规模高性能、高并发的网络架构经验分享

千万级规模高性能.高并发的网络架构经验分享 主 题 :INTO100沙龙时间 :2015年11月21日下午地点 :梦想加联合办公空间分享人:卫向军(毕业于北京邮电大学,现任微博平台架构师,先后在微软.金山云.新浪微博从事技术研发工作,专注于系统架构设计.音视频通讯系统.分布式文件系统和数据挖掘等领域.) 架构以及我理解中架构的本质 在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又 要 藐

千万级用户直播APP——服务端结构设计和思考

一直播产品是一下科技今年五月份刚上线的产品.得益于与微博的深度合作,以及与小咖秀.秒拍共同运营,一直播开始时就有一个很高的起点,短短半年内,达到同时在线用户百万级规模.在2016杭州云栖大会的"开发者技术峰会"上,来自一下科技的技术副总裁张华伟给大家解密了一直播千万级用户服务端架构设计和成长历程. 以下内容根据演讲PPT及现场分享整理. 直播行业是今年最为火爆的行业,作为新兴的产品形态,直播产品最大的特点是:快.推流速度足够快,主播通过移动端快速推流,用户能快速看到直播场景,延迟需要足

如何打造千万级Feed流系统

在互联网领域,尤其现在的移动互联网时代,Feed流产品是非常常见的,比如我们每天都会用到的朋友圈,微博,就是一种非常典型的Feed流产品,还有图片分享网站Pinterest,花瓣网等又是另一种形式的Feed流产品.除此之外,很多App的都会有一个模块,要么叫动态,要么叫消息广场,这些也是Feed流产品,可以说,Feed流产品是遍布天下所有的App中. 概念 我们在讲如何设计Feed流系统之前,先来看一下Feed流中的一些概念: Feed:Feed流中的每一条状态或者消息都是Feed,比如朋友圈中

总结:如何使用redis缓存加索引处理数据库百万级并发

前言:事先说明:在实际应用中这种做法设计需要各位读者自己设计,本文只提供一种思想.准备工作:安装后本地数redis服务器,使用mysql数据库,事先插入1000万条数据,可以参考我之前的文章插入数据,这里不再细说.我大概的做法是这样的,编码使用多线程访问我的数据库,在访问数据库前先访问redis缓存没有的话在去查询数据库,需要注意的是redis最大连接数最好设置为300,不然会出现很多报错. 贴一下代码吧 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 1

生日管家获千万级人民币A轮融资:主打情感纽带

生日管家推出的时间是2012年6月,目前其云端生日数据已积累至6000万,用户量约1000万,近日刚完成千万级人民币A轮融资.创始人沈悦雯表示,生日管家记录的不仅是一连串简单的数字,而是珍贵的情感纽带.生日管家的核心理念是以优秀的产品体验引领消费.用户从安装生日管家,记录生日,收到提醒,到社区里交流送礼心得,从线上下单购买,生日管家寻找合作商家,提供线下服务,并形成平台评价机制,用户有问题可以反馈,满意者可留言给好评,或在社区里晒出自己的开心时刻并得到他人的祝福,形成一个垂直的生态闭环.沈悦雯说