网卡流量和带宽
带宽
带宽是决定主机访问速度的重要因素之一,尤其是对于访问量大的网站,网络带宽的大小显得尤为重要。而流量其实就是带宽在时间上的积累,用数学上的话说就是带宽对时间的积分。做个通俗的比喻,拿自来水来说,带宽其实就是水管里水的流速,而流量就是流出的水的总量。
因为网络带宽和流量对于服务器来说至关重要,所以在选购服务器之前应该很好的了解这个概念,要么很容易被主机商忽悠。下面是带宽容易出现的几个误区。
一、容易混淆两个单位:字节和位
说到带宽,就会涉及到带宽的单位,带宽一般用 位 做单位,英文是bit,例如ADSL(释义传送门)的带宽是2Mb,实际上就是2Mbit每秒(2Mbit/s)。M就是兆,我们平时说的两兆网就是2M。
单位换算:1G=1024M 1M=1024K.
比特和位的关系
1字节(byte)=8位(bit)
缩写的时候两个都是b,习惯上byte缩写用大写的B,而bit用小写的b,但是很多时候书写很混乱,所以看到主机商写的带宽时,要先搞清楚是byte还是bit。
一般说机房带宽,主机端口带宽都是bit,但是有写主机限制峰值带宽,而这个有的主机商用的byte,有的用的bit。两个相差8倍,所以要先弄清楚。
二、共享和独享之分
这个虚拟主机一般不说,只有在主机租用和托管的时候会提到,因为虚拟主机肯定是分享一个服务器的带宽,没有独享的。但是因为虚拟主机的是从服务器上分出来的,所以还是明白服务器的带宽情况比较好。
国内常见的是100M共享和10M独享,100M共享其实就是一个机柜分享一个100M的端口,至于每台服务器能分到多少,取决于这个机柜的服务器数量和每个服务器的带宽占用情况。
而10M独享,就是给每台服务器一个10M的端口。一般来说,100M共享每台服务器分到的带宽大约在2M到5M左右,所以10M独享是优于100M共享的。
国内的虚拟主机用的服务器多数是100M共享,也有10M独享的,但是有人说他的服务器是100M独享的就要小心了,骗人的嫌疑很大。
除了以上说的,其实一个服务器能够分到的带宽还取决于整个机房的带宽是否允许。10M独享或者是100M独享其实只是10M端口或者100M端口接到了交换机上。做个极端的例子,假设机房给你100M的端口,但是机房到公网的出口实际上只有10M,那么其实你的最大带宽也就是10M而已。从这个意义上说,100M独享其实还是共享,并不是把你的出口接到了主干网上。再大一层次,如果某个主干网拥塞,就是给你1G端口接到主干网上,带宽照样会限制。所以独享和共享其实是相对的。
一般来说,接入一个机房的出口带宽是10G,分给服务器或者机柜的带宽累加值会大于这个值,也就是所谓的超卖。如果没有超卖,10G的带宽只能分给100个百M共享的机柜。因为并不是每台服务器每时每刻都会占满带宽,超卖会更充分利用资源。虚拟主机的带宽以及其他资源都和这个道理差不多,也会存在超卖的现象,但是只要是合理的,都是对用户和主机商有利的。
三、流量
做个通俗的比喻,拿自来水来说,带宽其实就是水管里水的流速,而流量就是流出的水的总量。
对于网络带宽控制,不少主机商,尤其是美国主机都会限制流量,那么我们就分析一下网站带宽大小指标流量的具体概念,感觉一下。
1、10M独享的服务器每月的最大流量:
带宽用的是bit,所以别忘记8倍差别。宽带带宽计算如下:
(10Mx3600x24x30) / (1024x8) = 3164GB
10M带宽传输速率是10M/8=1.25MB/s,也就是我们下载时看到的1.25M/s
1.25*3600秒*24小时*30天,再除1024(结果是G,1G=1024M)
也就是10M独享的服务器每月的流量上限是3000G,可以看出来,不管主机商是否明确写着限制流量,其实都是有上限的,只是写不写而已。上面计算的是理想状态,一般来说都是达不到最大带宽的。
一般来说,一台服务器上至少要放100个网站(很多都是几百个),那么如果平均算,每个网站分到的流量实际上只有30G每个月。
2、1G流量意味着什么?
假设你的一个页面是100KB,那么1G流量可以访问的页面是:(1*1024*1024)/100=10485,也就是说每天1G流量可以承受一万PV。很多个人网站是达不到这么大的pv的,所以很多网站每个月30G流量足够了。当然如果下载的话流量就可能会很大了。
另外,一个页面文件100K,访问时消耗的流量未必就是100K,浏览器都会缓存页面,很多元素是不会重复计算流量的。另外还可以通过gzip等方式降低流量占用。
所以,一般情况下,流量限制并没有多数人想象的那么可怕,而且不管主机商是否限制,起始都隐含了流量限制。如果你的服务器只有1M的带宽,你拼命的用,一个月也只能用掉300G而已。
上一篇: MB/s、Mb/s、Mbps、Mbit/s、Kbps
下一篇: 电脑基本知识
推荐阅读
-
数据速率、载波频率和带宽之间的关系
-
位、字节、WORD、DWORD 的区别和联系 - Unicode 和 ANSI 的区别就像输入法中 "全宽 "和 "半宽 "的区别一样。 由于不同的 ANSI 编码有不同的标准(不同的字符集),对于给定的多字节字符串,我们必须知道它使用的是哪种字符集,才能知道它包含哪些 "字符"。对于 UNICODE 字符串来说,无论环境如何,它所代表的 "字符 "内容始终是相同的。Unicode 有一个统一的标准,定义了世界上大多数字符的编码,因此拉丁文、数字、简体中文、繁体中文和日文都可以存储在一个编码中。统一码是一个统一的标准,定义了世界上大多数字符的编码。 比特(Bit)和字节(Byte)的区别:例如USB2.0 标准接口的传输速率为 480Mbps,有一些人误认为是每秒 480 兆比特,同样网络带宽为 2MB,就容易误认为是每秒 2 兆比特。其实,480Mbps 应该是 480 兆比特/秒或 480 兆字节/秒,它等于 "60 兆字节/秒";同样,2MB,应该是 256 兆字节/秒。 Bit 和 Byte 译为 "比特",都是数据计量单位,比特="位 "或 "比特"。 Byte = 字节,即 1byte = 8bits,两者的换算关系为 1:8。 Mbps = mega bits per second(兆位/秒)是速率单位,因此 2M 带宽应为 2 兆位/秒,即 2MBps。MB = 兆字节(Megabytes,兆字节)是单位量,1MB/S(兆字节/秒)= 8MBPS(兆字节/秒)。 通常所说的硬盘容量是指 40GB、80GB、100GB,其中的 B 是指 Byte 也称为 "字节"。 1 KB=1024 字节 1 MB=1024 KB=1024*1024 字节 1 GB=1024 MB=1024*1024*1024 字节 例如,以前所谓的 56KB MODEM 转换过来的 56KBps 除以 8 就是 7Kbyte,所以真正从网上下载文件存在硬盘上的速度也是每秒 7Kbyte;也就是说,用 B 表示传输速度一般指 Bit;用 B 表示容量一般指 Byte。比特、字节、WORD、DWORD 的本质。
-
带宽、Mbps、Kbps、bps、KB、MB 及其转换和区别
-
高并发技巧 - 流量聚合和高并发写入处理技巧
-
流量计安装图和安装点
-
深入分析网络性能:延迟、带宽、吞吐量和响应时间的奥秘,网络工程师文集!
-
计算机网络] 一文告诉你 localhost、127.0.0.1、本地 IP、公共 IP、专用 IP、网卡 (MAC) 和 IP ...
-
输出格式化(用量百分比和流量用量)
-
WINDOWS 网卡和 WIFI 覆盖解决方案
-
epoll简介及触发模式(accept、read、send)-epoll的简单介绍 epoll在LT和ET模式下的读写方式 一、epoll的接口非常简单,一共就三个函数:1. int epoll_create(int size);创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大。这个参数不同于select中的第一个参数,给出最大监听的fd+1的值。需要注意的是,当创建好epoll句柄后,它就是会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close关闭,否则可能导致fd被耗尽。2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epoll的事件注册函数,它不同与select是在监听事件时告诉内核要监听什么类型的事件,而是在这里先注册要监听的事件类型。第一个参数是epoll_create的返回值,第二个参数表示动作,用三个宏来表示:EPOLL_CTL_ADD:注册新的fd到epfd中;EPOLL_CTL_MOD:修改已经注册的fd的监听事件;EPOLL_CTL_DEL:从epfd中删除一个fd;第三个参数是需要监听的fd,第四个参数是告诉内核需要监听什么事,struct epoll_event结构如下:struct epoll_event { __uint32_t events; /* Epoll events */ epoll_data_t data; /* User data variable */};events可以是以下几个宏的集合:EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭); EPOLLIN事件:EPOLLIN事件则只有当对端有数据写入时才会触发,所以触发一次后需要不断读取所有数据直到读完EAGAIN为止。否则剩下的数据只有在下次对端有写入时才能一起取出来了。现在明白为什么说epoll必须要求异步socket了吧?如果同步socket,而且要求读完所有数据,那么最终就会在堵死在阻塞里。 EPOLLOUT:表示对应的文件描述符可以写; EPOLLOUT事件:EPOLLOUT事件只有在连接时触发一次,表示可写,其他时候想要触发,那要先准备好下面条件:1.某次write,写满了发送缓冲区,返回错误码为EAGAIN。2.对端读取了一些数据,又重新可写了,此时会触发EPOLLOUT。简单地说:EPOLLOUT事件只有在不可写到可写的转变时刻,才会触发一次,所以叫边缘触发,这叫法没错的!其实,如果真的想强制触发一次,也是有办法的,直接调用epoll_ctl重新设置一下event就可以了,event跟原来的设置一模一样都行(但必须包含EPOLLOUT),关键是重新设置,就会马上触发一次EPOLLOUT事件。1. 缓冲区由满变空.2.同时注册EPOLLIN | EPOLLOUT事件,也会触发一次EPOLLOUT事件这个两个也会触发EPOLLOUT事件 EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);EPOLLERR:表示对应的文件描述符发生错误;EPOLLHUP:表示对应的文件描述符被挂断;EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);等待事件的产生,类似于select调用。参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。-------------------------------------------------------------------------------------------- 从man手册中,得到ET和LT的具体描述如下EPOLL事件有两种模型:Edge Triggered (ET)Level Triggered (LT)假如有这样一个例子:1. 我们已经把一个用来从管道中读取数据的文件句柄(RFD)添加到epoll描述符2. 这个时候从管道的另一端被写入了2KB的数据3. 调用epoll_wait(2),并且它会返回RFD,说明它已经准备好读取操作4. 然后我们读取了1KB的数据5. 调用epoll_wait(2)......Edge Triggered 工作模式:如果我们在第1步将RFD添加到epoll描述符的时候使用了EPOLLET标志,那么在第5步调用epoll_wait(2)之后将有可能会挂起,因为剩余的数据还存在于文件的输入缓冲区内,而且数据发出端还在等待一个针对已经发出数据的反馈信息。只有在监视的文件句柄上发生了某个事件的时候 ET 工作模式才会汇报事件。因此在第5步的时候,调用者可能会放弃等待仍在存在于文件输入缓冲区内的剩余数据。在上面的例子中,会有一个事件产生在RFD句柄上,因为在第2步执行了一个写操作,然后,事件将会在第3步被销毁。因为第4步的读取操作没有读空文件输入缓冲区内的数据,因此我们在第5步调用 epoll_wait(2)完成后,是否挂起是不确定的。epoll工作在ET模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。最好以下面的方式调用ET模式的epoll接口,在后面会介绍避免可能的缺陷。 i 基于非阻塞文件句柄 ii 只有当read(2)或者write(2)返回EAGAIN时才需要挂起,等待。但这并不是说每次read时都需要循环读,直到读到产生一个EAGAIN才认为此次事件处理完成,当read返回的读到的数据长度小于请求的数据长度时,就可以确定此时缓冲中已没有数据了,也就可以认为此事读事件已处理完成。Level Triggered 工作模式相反的,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll(2),并且无论后面的数据是否被使用,因此他们具有同样的职能。因为即使使用ET模式的epoll,在收到多个chunk的数据的时候仍然会产生多个事件。调用者可以设定EPOLLONESHOT标志,在 epoll_wait(2)收到事件后epoll会与事件关联的文件句柄从epoll描述符中禁止掉。因此当EPOLLONESHOT设定后,使用带有 EPOLL_CTL_MOD标志的epoll_ctl(2)处理文件句柄就成为调用者必须作的事情。然后详细解释ET, LT:LT(level triggered)是缺省的工作方式,并且同时支持block和no-block socket.在这种做法中,内核告诉你一个文件描述符是否就绪了,然后你可以对这个就绪的fd进行IO操作。如果你不作任何操作,内核还是会继续通知你的,所以,这种模式编程出错误可能性要小一点。传统的select/poll都是这种模型的代表.ET(edge-triggered)是高速工作方式,只支持no-block socket。在这种模式下,当描述符从未就绪变为就绪时,内核通过epoll告诉你。然后它会假设你知道文件描述符已经就绪,并且不会再为那个文件描述符发送更多的就绪通知,直到你做了某些操作导致那个文件描述符不再为就绪状态了(比如,你在发送,接收或者接收请求,或者发送接收的数据少于一定量时导致了一个EWOULDBLOCK 错误)。但是请注意,如果一直不对这个fd作IO操作(从而导致它再次变成未就绪),内核不会发送更多的通知(only once),不过在TCP协议中,ET模式的加速效用仍需要更多的benchmark确认(这句话不理解)。在许多测试中我们会看到如果没有大量的idle -connection或者dead-connection,epoll的效率并不会比select/poll高很多,但是当我们遇到大量的idle- connection(例如WAN环境中存在大量的慢速连接),就会发现epoll的效率大大高于select/poll。(未测试)另外,当使用epoll的ET模型来工作时,当产生了一个EPOLLIN事件后,读数据的时候需要考虑的是当recv返回的大小如果等于请求的大小,那么很有可能是缓冲区还有数据未读完,也意味着该次事件还没有处理完,所以还需要再次读取: 这里只是说明思路(参考《UNIX网络编程》) while(rs) {buflen = recv(activeevents[i].data.fd, buf, sizeof(buf), 0);if(buflen < 0){// 由于是非阻塞的模式,所以当errno为EAGAIN时,表示当前缓冲区已无数据可读// 在这里就当作是该次事件已处理处.if(errno == EAGAIN)break; else return; }else if(buflen == 0) { // 这里表示对端的socket已正常关闭. } if(buflen == sizeof(buf) rs = 1; // 需要再次读取 else rs = 0; } 还有,假如发送端流量大于接收端的流量(意思是epoll所在的程序读比转发的socket要快),由于是非阻塞的socket,那么send函数虽然返回,但实际缓冲区的数据并未真正发给接收端,这样不断的读和发,当缓冲区满后会产生EAGAIN错误(参考man send),同时,不理会这次请求发送的数据.所以,需要封装socket_send的函数用来处理这种情况,该函数会尽量将数据写完再返回,返回-1表示出错。在socket_send内部,当写缓冲已满(send返回-1,且errno为EAGAIN),那么会等待后再重试.这种方式并不很完美,在理论上可能会长时间的阻塞在socket_send内部,但暂没有更好的办法. ssize_t socket_send(int sockfd, const char* buffer, size_t buflen) { ssize_t tmp; size_t total = buflen; const char *p = buffer; while(1) { tmp = send(sockfd, p, total, 0); if(tmp < 0) { // 当send收到信号时,可以继续写,但这里返回-1. if(errno == EINTR) return -1; // 当socket是非阻塞时,如返回此错误,表示写缓冲队列已满, // 在这里做延时后再重试. if(errno == EAGAIN) { usleep(1000); continue; } return -1; } if((size_t)tmp == total) return buflen; total -= tmp; p += tmp; } return tmp; } 二、epoll在LT和ET模式下的读写方式 在一个非阻塞的socket上调用read/write函数, 返回EAGAIN或者EWOULDBLOCK(注: EAGAIN就是EWOULDBLOCK) 从字面上看, 意思是: * EAGAIN: 再试一次 * EWOULDBLOCK: 如果这是一个阻塞socket, 操作将被block * perror输出: Resource temporarily unavailable 总结: 这个错误表示资源暂时不够, 可能read时, 读缓冲区没有数据, 或者, write时,写缓冲区满了 。 遇到这种情况, 如果是阻塞socket, read/write就要阻塞掉。 而如果是非阻塞socket, read/write立即返回-1, 同 时errno设置为EAGAIN. 所以, 对于阻塞socket, read/write返回-1代表网络出错了. 但对于非阻塞socket, read/write返回-1不一定网络真的出错了. 可能是Resource temporarily unavailable. 这时你应该再试, 直到Resource available. 综上, 对于non-blocking的socket, 正确的读写操作为: 读: 忽略掉errno = EAGAIN的错误, 下次继续读 写: 忽略掉errno = EAGAIN的错误, 下次继续写 对于select和epoll的LT模式, 这种读写方式是没有问题的. 但对于epoll的ET模式, 这种方式还有漏洞. epoll的两种模式 LT 和 ET