C10K-C10M进阶(高并发的真正理解)

news2024/11/24 16:04:46

1、一台计算机可以连接的TCP受什么限制?
能打开文件描述符的限制。默认是1024,可以修改。
端口号的限制,65535,因为TCP头部16位的端口号,其中1024以上可以用。如果是客户端,最多可以打开6万多的文件。如果是服务器,还要乘以ip数量。
但是,最终TCP连接数量还是会收到内存、操作系统等限制,不过现在达到数十万应该没问题。

C10K问题
早期网站100人就很多了,后来web1.0时代,人变多了,但也只是简单下载html浏览网页。但是到2.0时代,用户几何增长,而且不仅仅是简单浏览,有复杂的交互。所以网站同一时间的并发TCP连接很可能已经过亿。最初的服务器都是基于进程/线程模型的(典型的就是apache多线程),新到来一个TCP连接,就需要分配1个进程(或者线程)。而进程又是操作系统最昂贵的资源,一台机器无法创建很多进程。如果是C10K就要创建1万个进程,那么单机而言操作系统是无法承受的。

特点: 性能和连接数及机器性能的关系往往是非线性的。它在 2 倍性能新服务器上往往处理不了并发 2倍的吞吐量。这是因为在策略不当时,大量操作的消耗和当前连接数 n 成线性相关。会导致单个任务的资源消耗和当前连接数的关系会是 O(n)
连接数越多,那么单个连接消耗的时间越长。

**本质:**操作系统的问题。同步阻塞I/O模型。创建的进程线程多了,数据拷贝频繁(磁盘文件-page cache-用户-内核socket缓冲区-网卡), 进程/线程上下文切换消耗大, 导致操作系统崩溃,榨干了CPU资源,这就是C10K问题的本质!
(线程切换和线程数量有关,因为要线性查找可以用的空闲线程,所以要epoll来使线程切换和线程数量无关)

解决方案: 非阻塞IO+IO复用机制
给每个连接分配一个进程,不现实的;
也就是等有数据到才分配线程去处理,避免无意义的上下文切换。

select使用fd_set,检查是否发生事件。缺点是fd_set大小限制,拷贝开销和逐个检查以及重复初始化的开销。
poll 主要解决 select 的前两个问题:通过一个 pollfd 数组向内核传递需要关注的事件消除文件句柄上限,同时使用不同字段分别标注关注事件和发生事件,来避免重复初始化。
epoll如果调用返回的时候只给应用提供发生了状态变化(很可能是数据 ready)的文件句柄
由于epoll, kqueue, IOCP每个接口都有自己的特点,程序移植非常困难,于是需要对这些接口进行封装,以让它们易于使用和移植,其中libevent库就是其中之一
(其实这些只是解决了线程切换的问题,数据拷贝的问题没有解决,利用sendfile零拷贝技术可能会效果更好)

总结一下就是不要让CPU处理无关的事情,比如阻塞等待数据到达,比如处理进程的上下文切换,创建销毁,数据拷贝等。
充分利用CPU。

解决C10M问题并非不可能
OS的内核不是解决C10M问题的办法,恰恰相反OS的内核正是导致C10M问题的关键所在。
截至目前,40gpbs、32-cores、256G RAM的X86服务器在Newegg网站上的报价是几千美元。实际上以这样的硬件配置来看,它完全可以处理1000万个以上的并发连接,如果它们不能,那是因为你选择了错误的软件,而不是底层硬件的问题。

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

比如微软的DPDK就是设计了数据面快速路径等。

1、要知道linux内核一开始就是一个分时系统,最重要的是保证公平性,CFS算法。而我们的实际任务可能会有差别,所以最好把调度让应用程序完成,减轻内核调度的负担以及无意义的调度;
2、核绑定,任务可能会在不同的CPU核上运行,尤其现在是NUMA架构,会导致上下文的切换,以及cache命中率的问题;
3、数据包直接和应用层交互,Linux协议栈是复杂和繁琐的,数据包经过它无非会导致性能的巨大下降,并且会占用大量的内存资源。比如DPDK的网卡驱动就是在应用层,数据不经过内核。(当然发给自己的数据包肯定要经过内核)
4、大页机制的开启,减少地址转换开销。(4kb-2mb)

IO模型探索
一个典型的IO涉及到4次拷贝。
1.服务端请求接收,read过程。请求磁盘/网卡拷贝到内核page,再拷贝到用户处理;write,处理完后,拷贝到socket内核缓存,再拷贝到网卡发送;

设计服务端并发模型时,主要有如下两个关键点:
1)服务器如何管理连接,获取输入数据; (阻塞、非阻塞轮询、IO复用、信号)
2)服务器如何处理请求。
线程池、多线程、单线程

一个输入操作通常包括两个不同的阶段:
1)等待数据准备好;
2)从内核向进程复制数据。

阻塞IO:就是数据没来一直等,等待期间挂起线程。一般这种需要每个连接一个线程,很少用。优点是阻塞不占用CPU

非阻塞式 I/O:没有数据不会阻塞,而是一直轮询,实时性比较好。轮询将会不断地询问内核,这将占用大量的 CPU 时间,系统资源利用率较低,所以一般 Web 服务器不使用这种 I/O 模型。

I/O 复用:不用CPU轮询了,一旦有准备好的数据会通知你。既没有CPU消耗,又使用一个描述符就可以监听大量socket节省资源;

信号驱动式 I/O 模型:当数据准备好时,进程会收到一个 SIGIO 信号,可以在信号处理函数中调用 I/O 操作函数处理数据。
优点:线程并没有在等待数据时被阻塞,可以提高资源的利用率。IO复用没有数据时还会阻塞呢
信号驱动 I/O 尽管对于处理 UDP 套接字来说有用,即这种信号通知意味着到达一个数据报,或者返回一个异步错误。
但是,对于 TCP 而言,信号驱动的 I/O 方式近乎无用,因为导致这种通知的条件为数众多(因为有连接状态,比如连接完成、连接关闭、关闭连接请求发起,完成等等),每一个来进行判别会消耗很大资源,信号会产生中断上下文切换,与前几种方式相比优势尽失。

以上几种都是同步IO模型
异步 I/O 模型
同步IO指的是,第二阶段(数据到达后从内核拷贝到用户态需要自己参与)
为什么我们明明是想读取数据,什么非得要先发起一个select询问数据状态的请求,然后再发起真正的读取数据请求,能不能有一种一劳永逸的方式,我只要发送一个请求我告诉内核我要读取数据,然后我就什么都不管了,然后内核去帮我去完成剩下的所有事情?
效率最高,阻塞最少。
但是这需要操作系统做很多事情,但是这种方式还不稳定,目前只有windows的IOAP,linux后来也有AIO但是不稳定,所以主要用的还是IO复用技术

上面介绍的是如何处理连接,获取输入?
下面介绍如何处理请求?
1.每个连接一个线程。问题很多,并发量大时内存占用大;没有数据时会阻塞;线程频繁创建销毁也需要CPU;

2、Reactor 模式
最经典的就是IO复用+线程池。reactor单线程(redis就是这种)、reactor多线程、主从reactor模式(IO事件读取也会耗时,分给多个从reactor读)
这里要考虑瓶颈到底是IO事件分发部分,还是线程池处理部分。一般而言,是线程池,因为线程数目一般和核数相同或者略多4,8个。而我们一般会并发100,1000,10000个客户端,线程池是很忙的,就算从reactor减小了就绪IO的分配事件,只会导致线程池的队列变长。等待处理,还有可能导致队列溢出。
(这里重点来了,我们分析了**,IOaccept以及IO监听分发不是瓶颈,瓶颈是处理请求来不及,而最大的弊端在于:消息队列因为是多线程取消息,需要加锁的。所以大大降低了速度。如何降低线程池中消息队列消息取的速度非常重要。**)

Proactor 模型
我们发现reactor非阻塞同步模型。也就是等待IO就绪不阻塞,但是数据从内核拷贝到用户这段时间线程需要等待的。最好就是异步给操作系统来完成就好了。要使用异步IO
缺点:编程复杂性, Linux 系统下,Linux 2.6 才引入,目前异步 I/O 还不完善。内存使用,缓冲区在读或写操作的时间段内必须保持住,可能造成持续的不确定性,并且每个并发操作都要求有独立的缓存,相比 Reactor 模式,在 Socket 已经准备好读或写前,是不要求开辟缓存的;

什么是高并发
它通常是指单位时间内系统能够同时处理的请求数。简单点说,就是QPS

注意:高并发实际上就是对CPU资源的有效压榨。对于加密解密这种计算密集的任务,谈高并发没有意义,因为CPU一直在使用的。加机器就行了。
我们讨论的是IO密集型的包括网络数据库IO。

控制变量法
(这里可以谈一下为什么我们只做了服务器层,没有涉及到其它层,因为对于高并发来说,每一层都可能是瓶颈,我们主要研究服务层有哪些可以提高并发的方法)
在这里插入图片描述
要达到高并发,我们需要负载均衡、服务层、缓存层、持久层都是高可用、高性能的。甚至在第5步,我们也可以通过压缩静态文件、HTTP2推送静态文件、CDN来做优化,这里的每一层我们都可以写几本书来谈优化。
本文主要讨论服务层这一块,即图红线圈出来的那部分。不再考虑讲述数据库、缓存相关的影响。

在这里插入图片描述
这一步步的都是对CPU资源的层层压榨,让他最大程度不阻塞,不干别的事(上下文切换,数据拷贝等)
协程没有用户态到内核态的切换了,因为只是指针变了一下而已。这里说一下我们的协程和rust,go协程区别。
协程的另一个优点是同步写法实现异步性能。

反正测试的时候要尽可能让CPU利用率跑满,不要阻塞。并且确保它们是在做正确的事,不是在处理上下文切换,线程创建销毁,数据拷贝、地址翻译、CPU多核跨越访问、中断等。
C10M也是同样的思想。

找到问题,往往比解决问题更难。当我们理解了高并发之后,我们会发现高并发和高性能并不是编程语言限制了你,限制你的只是你的思想。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/558895.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

车载测试之车联网OTA安全实践

在SDV的大趋势下,汽车零部件智能化水平不断提高,车辆内部搭载的软件也越来越多。毫无疑问,车辆复杂度的提高必将带来维护上的困难,车企要如何面对更新迭代速度越来越快的软件、固件系统?OTA(over the air&a…

论文笔记: Trajectory Clustering: A Partition-and-Group Framework

07 Sigmoid 使用类DBSCAN的思路对轨迹聚类 1 intro 1.1 轨迹聚类 现有的轨迹聚类算法是将相似的轨迹作为一个整体进行聚类,从而发现共同的轨迹。 但是这样容易错过一些共同的子轨迹(sub-trajectories)。而在实际中,当我们对特…

运行 100 万个并发任务需要多少内存?

在这篇博文中,我深入研究了 Rust、Go、Java、C#、Python、Node.js 和 Elixir 等流行语言在异步和多线程编程之间的内存消耗比较。 前段时间,我不得不比较一些旨在处理大量网络连接的计算机程序的性能。我看到这些程序的内存消耗存在巨大差异&#xff0c…

【Atlas200】华为AIPP配置文件使用

目录 AIPP介绍图像处理顺序例子:YUV420SP_U8转BGR格式归一化配置对应公式crop及padding功能配置生效AIPP转换模板 AIPP介绍 华为的AIPP(AI Preprocessing)是一种面向AI应用的图像预处理技术,旨在提高AI应用的效率和精度。AIPP支持…

C语言深度解析--数组

目录 一维数组的创建与初始化 一维数组的创建: 一维数组的初始化: 一维数组的使用: 一维数组在内存中的存储: 二维数组的创建与初始化 二维数组的创建: 二维数组的初始化: 二维数组的使用&#xf…

是面试官放水,还是公司太缺人了?华为原来这么容易就进了...

华为是大企业,是不是很难进去啊?” “在华为做软件测试,能得到很好的发展吗? 一进去就有9.5K,其实也没有想的那么难” 直到现在,心情都还是无比激动! 本人211非科班,之前在字节和腾…

以“智”提质丨信创呼叫

随着人工智能、大数据、云计算等新兴技术飞速发展,呼叫中心、全媒体智能客服等现已被广泛应用于多个行业领域。其中,呼叫中心作为政企对外服务的重要窗口,已从“传统电话营销”发展到“智能呼叫中心”阶段,以客户服务为核心&#…

Windows下Elasticsearch下载安装

Windows下Elasticsearch下载安装 最近搭一个语义搜索web需要用到es。 1.下载 下载地址:官网下载地址 下载zip格式解压就行,这里我下载的是8.7.1 1.1解压启动 解压之后,进入elasticsearch的bin目录,通过点击elasticsearch.ba…

0基础学习VR全景平台篇第28章:场景管理—遮罩功能

本期为大家带来蛙色VR平台,场景管理模块-遮罩功能! 功能位置示意 一、本功能将用在哪里? 遮罩分为两种,分别是地面遮罩和天空遮罩。 地面遮罩位于全景图底部的正中间,天空遮罩位于全景图顶部的正中间。 遮罩一方面可…

已解决python使用pymysql向mysql数据库插入数据报错pymysql.err.DataError: (1366, ‘‘)

已解决,在python代码是使用pymysql向mysql数据库插入数据时报错pymysql.err.DataError: (1366, ) 问题描述 我从某个网页上抓取并解析了一段html代码,然后将html代码转为utf-8格式,之后将html代码作为数据表的一个属性存入mysql数据库中&…

代码签名证书,保护应用程序安全性

在现代IT环境中,有大量不同的方式可以用来确保应用程序的安全性。其中一个就是从源头开始,让应用程序开发者能够对他们的代码进行数字签名,从而确保给定应用程序的完整性和真实性。 一直以来,认证机构安理会(CASC&…

2023年必备的10款交互设计软件

交互设计可以帮助明确产品需求和功能、进行用户测试和获取反馈、减少开发成本、促进团队合作,并在展示和推销产品时起到关键作用。通过有效的产品交互设计,可以提高产品的质量、用户体验和市场竞争力。 什么是产品交互设计? 产品交互设计是…

Linux查看磁盘利用率(iostat)

使用iostat命令可以查看磁盘的负载情况。iostat命令可以显示磁盘的I/O统计信息,包括磁盘的读写速度、I/O请求队列长度、CPU利用率等。 参数 Device:磁盘分区的名称。rrqm/s:每秒钟合并的读请求。wrqm/s:每秒钟合并的写请求。r/s…

11-FastDFS文件服务器 和 Nginx

1、什么是FastDFS 1、开源的轻量级分布式文件系统,用于解决大数据量存储和负载均衡等问题。 2、优点: 支持HTTP协议传输文件(结合Nginx); 对文件内容做Hash处理,节约磁盘空间; 支持负载均衡、整体性能较佳。 3、FastDFS的二个角色:跟踪服务器(Tracker)、存储服务器…

StringBuffer与StringBuilder的区别

🏆今日学习目标: 🍀StringBuffer与StringBuilder的区别 ✅创作者:林在闪闪发光 ⏰预计时间:30分钟 🎉个人主页:林在闪闪发光的个人主页 🍁林在闪闪发光的个人社区,欢迎你…

档案馆库房温湿度监控系统简单介绍

智慧档案馆八防一体化监控系统 智慧档案平台/温湿度/空气质量/漏水/视频/门禁/一体化管控平台 HONSOR多维空间可视化智慧档案库房建设一体化平台分享 三维可视化智慧档案馆库房一体化环境安全管控系统平台 1.系统告警要求: (1)告警方式&am…

[PCIE733]基于PCI Express总线架构的2路160MSPS AD采集、12路LVDS图像数据采集卡

板卡概述 PCIE733是一款基于PCI Express总线架构的,实现2路16-bit、160MSPS ADC采集功能、12路LVDS数据采集板卡。该板卡遵循PCI Express 2.0规范,全高半长尺寸,板卡采用Xilinx的28nm高性能FPGA处理器XC7K325T作为主控制器,板卡AD…

【dfs序+线段树】P3178 [HAOI2015]树上操作

这道题,昨天调到一点多都没调出来,眼睛都要瞎了 今天看着题解边看边调出来了,但是还是感觉不是很会 m d,学的第一道关于树的DS就搞成这样 感觉很寄啊 P3178 [HAOI2015]树上操作 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)…

事务、分布式事务以及seata

事务 事务就是用户定义的一系列数据库操作,这些操作可以视为一个完成的逻辑处理工作单元,要么全部执行,要么全部不执行,是不可分割的工作单元。 事务的四个特效ACID Atomic 原子性,原子性是指事务必须是一个原子的操…

手摸手教你Vite+Vue3项目初始化及开源部署到GItee

项目初始化 本片文章主要记录项目的环境,项目搭建。 在开始本次学习中,鉴于你有前端三件套和vue的知识基础。 文档创建于2023年5月20日,大家都去过情人节了~我在肝代码! 环境的搭建 node版本使用18.16.0。 目前(202…