C10K问题

C10K问题就是如何一台物理机上同时服务10000个用户?C代表并发,10K就是10000

C10K 问题是由一个叫 Dan Kegel 的工程师提出并总结归纳的,你可以通过访问http://www.kegel.com/c10k.html获取最新相关信息

操作系统层面

C10K问题本质是一个操作系统给的问题,要在一台主机上同时支持1万个连接,意味着什么?需要考虑哪些方面?

文件句柄

每个客户连接就代表着一个文件描述符,一旦文件描述符不够用,新的连接就会被放弃。

在Linux中,单个进程打开的文件句柄数是有限制的,默认都是1024,可通过ulimit -n查看

但这个连接上线可通过修改/etc/sysctl.conf文件,使得系统可以支持10000个描述符上限。

fs.file-max = 10000
net.ipv4.ip_conntrack_max = 10000
net.ipv4.netfilter.ip_conntrack_max = 10000

系统内存

每个TCP连接都需要占用一定的发送缓冲区和接受缓冲器等内存资源。

在Linux 4.4.0下发送缓冲区和接受缓冲区的值。

$cat   /proc/sys/net/ipv4/tcp_wmem
4096 16384 4194304
$ cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 6291456

分别代表着最小分配值、默认分配值和最大分配值,按照默认分配值计算,一万个连接需要的内存消耗就是:

发送缓冲区: 16384*10000 = 160M bytes
接收缓冲区: 87380*10000 = 880M bytes

应用程序也需要一定的缓冲区来进行数据的收发,为方便,假设每个连接需要128K的缓冲区,那么1万个连接就需要1.2G的应用层缓冲。

网络宽带

假设 1 万个连接,每个连接每秒传输大约 1KB 的数据,那么带宽需要 10000 x 1KB/s x8 = 80Mbps。这在今天的动辄万兆网卡的时代简直小菜一碟

C10K问题解决之道

要想解决 C10K 问题,就需要从两个层面上来统筹考虑。

  • 第一个层面,应用程序如何和操作系统配合,感知 I/O 事件发生,并调度处理在上万个套接字上的 I/O 操作?
  • 第二个层面,应用程序如何分配进程、线程资源来服务上万个连接?

基于上面两个层次的组合形成了解决C10K问题的几种解决方案。

阻塞I/O + 进程

每个连接通过 fork 派生一个子进程进行处理,因为一个独立的子进程负责处理了该连接所有的 I/O,所以即便是阻塞 I/O,多个连接之间也不会互相影响。

这个方法虽然简单,但是效率不高,扩展性差,资源占用率高。

伪代码描述了使用阻塞 I/O,为每个连接 fork 一个进程的做法:

do{
accept connections
fork for conneced connection fd
process_run(fd)
}

阻塞I/O + 线程

通过为每个连接调用 pthread_create 创建一个单独的线程,也可以达到上面使用进程的效果。

do{
accept connections
pthread_create for conneced connection fd
thread_run(fd)
}while(true)

因为线程的创建是比较消耗资源的,况且不是每个连接在每个时刻都需要服务,因此可预先通过创建一个线程池,并在多个连接中复用线程池来获得某种效率的提升。

create thread pool
do{
accept connections
get connection fd
push_queue(fd)
}while(true)

非阻塞I/O + readiness notification + 单线程

应用程序其实可以采取轮询的方式来对保存的套接字集合进行挨个询问,从而找出需要进行 I/O 处理的套接字,像给出的伪码一样,其中 is_readble 和 is_writeable 可以通过对套接字调用 read 或 write 操作来判断。

for fd in fdset{
if(is_readable(fd) == true){
handle_read(fd)
}else if(is_writeable(fd)==true){
handle_write(fd)
}
}

操作系统来告诉我们哪个套接字可以读,哪个套接字可以写,采用select、poll这样的I/O分发技术。


do {
poller.dispatch()
for fd in registered_fdset{
if(is_readable(fd) == true){
handle_read(fd)
}else if(is_writeable(fd)==true){
handle_write(fd)
}
}while(ture)

epoll设计如下:


do {
poller.dispatch()
for fd_event in active_event_set{
if(is_readable_event(fd_event) == true){
handle_read(fd_event)
}else if(is_writeable_event(fd_event)==true){
handle_write(fd_event)
}
}while(ture)

非阻塞I/O + readiness notification + 多线程

把线程引入进来,可以利用现代 CPU 多核的能力,让每个核都可以作为一个 I/O 分发器进行 I/O 事件的分发。这就是所谓的主从 reactor 模式

基于 epoll/poll/select 的 I/O 事件分发器可以叫做 reactor,也可以叫做事件驱动,或者事件轮询(eventloop)。

异步I/O + 多线程

异步非阻塞 I/O 模型是一种更为高效的方式,当调用结束之后,请求立即返回,由操作系统后台完成对应的操作,当最终操作完成,就会产生一个信号,或者执行一个回调函数来完成 I/O 处理。

涉及到了Linux下的aio机制。

网络编程:C10K问题的更多相关文章

  1. 网络编程——C10K简述

    C10K问题   网络服务在处理数以万计的客户端连接时,往往出现效率底下甚至完全瘫痪,这被成为C10K问题. (C10K = connection 10 kilo 问题).k 表示 kilo,即 10 ...

  2. 网络编程——The C10K Problem(C10K = connection 10 kilo 问题)。k 表示 kilo,即 1000

    The C10K problem翻译 (C10K = connection 10 kilo 问题).k 表示 kilo,即 1000 比如:kilometer(千米), kilogram(千克). 如 ...

  3. 浅谈TCP/IP网络编程中socket的行为

    我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉: 1. TCP/IP协议(如连接的建立和终止.重传和确认.滑动窗口和拥塞控制等等) 2. Socket I/O系统 ...

  4. 不为人知的网络编程(八):从数据传输层深度解密HTTP

    1.引言 在文章<理论联系实际:Wireshark抓包分析TCP 3次握手.4次挥手过程>中,我们学会了用wireshark来分析TCP的“三次握手,四次挥手”,非常好用.这就是传说中的锤 ...

  5. 网络编程中TCP基础巩固以及Linux打开的文件过多文件句柄的总结

    1.TCP连接(短链接和长连接) 什么是TCP连接?TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的.可靠的.基于字节流的传输层通信协议. 当网络通信 ...

  6. 脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?

    本文引用了“帅地”发表于公众号苦逼的码农的技术分享. 1.引言 搞网络通信应用开发的程序员,可能会经常听到外网IP(即互联网IP地址)和内网IP(即局域网IP地址),但他们的区别是什么?又有什么关系呢 ...

  7. 脑残式网络编程入门(五):每天都在用的Ping命令,它到底是什么?

    本文引用了公众号纯洁的微笑作者奎哥的技术文章,感谢原作者的分享. 1.前言   老于网络编程熟手来说,在测试和部署网络通信应用(比如IM聊天.实时音视频等)时,如果发现网络连接超时,第一时间想到的就是 ...

  8. 脑残式网络编程入门(三):HTTP协议必知必会的一些知识

    本文原作者:“竹千代”,原文由“玉刚说”写作平台提供写作赞助,原文版权归“玉刚说”微信公众号所有,即时通讯网收录时有改动. 1.前言 无论是即时通讯应用还是传统的信息系统,Http协议都是我们最常打交 ...

  9. 脑残式网络编程入门(二):我们在读写Socket时,究竟在读写什么?

    1.引言 本文接上篇<脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手>,继续脑残式的网络编程知识学习 ^_^. 套接字socket是大多数程序员都非常熟悉的概念,它是计算机 ...

  10. 脑残式网络编程入门(一):跟着动画来学TCP三次握手和四次挥手

    .引言 网络编程中TCP协议的三次握手和四次挥手的问题,在面试中是最为常见的知识点之一.很多读者都知道“三次”和“四次”,但是如果问深入一点,他们往往都无法作出准确回答. 本篇文章尝试使用动画图片的方 ...

随机推荐

  1. nginx 如何强制跳转 https

    本项目 nginx 作为代理服务 项目上线,客户说要加个安全证书 ,于是安全证书是加上了,可是htttp和https都能访问网站,客户要求不行必须强制用带有https的地址访问 开整 这是 http ...

  2. mysql中,让自动增长字段值复位/重新计数

    在使用mysql时,常常要设置一个id值,并设置为自动增长 如果想要复位重新计数的话,那么应该使用以下语句 ALTER TABLE `表名` AUTO_INCREMENT = 1; 但需要注意的是,除 ...

  3. MyBatis mapper.xml中SQL处理小于号与大于号 和小于等于号

    这种问题在xml处理sql的程序中经常需要我们来进行特殊处理. 其实很简单,我们只需作如下替换即可避免上述的错误: < <= > >= & ' " < ...

  4. LCP 1. 猜数字

    地址:https://leetcode-cn.com/problems/guess-numbers/ <?php /** 小A 和 小B 在玩猜数字.小B 每次从 1, 2, 3 中随机选择一个 ...

  5. 晶振测试仪GDS-80系列参数

    晶振测试仪GDS-80系列 一.产品简介 晶振测试仪GDS-80系列是高性价比的晶振测试系统,采用网络分析技术,实现智能化测量,符合IEC-444标准.测量频率范围10KHz-200KHz,1MHz- ...

  6. 【ABAQUS Material】density 行为

    1.overview 进行eigenfrequency . transient dynamic analysis. transient heat transfer analysis. adiabati ...

  7. Ansible忽略任务失败

    在默认情况下,任务失败时会中止剧本任务,不过可以通过忽略失败的任务来覆盖此类行为.在可能出错且不影响全局的段中使用ignore_errors关键词来达到目的. 环境: 受控主机清单文件: [dev] ...

  8. matplotlib -- 绘图操作 -- 数据分析三剑客

    博客地址:https://www.cnblogs.com/zylyehuo/ 开发环境 anaconda 集成环境:集成好了数据分析和机器学习中所需要的全部环境 安装目录不可以有中文和特殊符号 jup ...

  9. win10/11 禁用移动热点,无法启用

    将网络重制即可

  10. 寻找可靠的长久的存储介质之旅,以及背后制作的三个网页“图片粘贴转base64”、“生成L纠错级别的QR码”、“上传文件转 base64以及粘贴 base64 转可下载文件”

    其实对于目前的形式来说,虽然像 U 盘.固态硬盘.甚至光盘这些信息储存介质(设备)的容量越来越高,但是不得不说这些设备的可靠性依然像悬着的一块石头,虽然这块石头确实牢牢的粘在天花板上,但是毕竟是粘上去 ...