菜菜哥,有个事你还得帮我呀程序员
呦西,YY妹子,最近天这么热了,你怎么还穿这么多?golang
苦笑一下.....前几天写了几个接口,领导让提升一下接口吞吐量面试
这是你技术提升的大好机会呀数据库
可吞吐量是什么呀?怎么提升呢?编程
来,凑近一点,哥给你解释一番缓存
百科服务器
吞吐量是指对网络、设备、端口、虚电路或其余设施,单位时间内成功地传送数据的数量(以比特、字节、分组等测量)。网络
以上的定义比较宽泛,定义到网站或者接口的吞吐量是这样的:吞吐量是指系统在单位时间内处理请求的数量。这里有一个注意点就是单位时间内,对于网站的吞吐量这个单位时间通常定义为1秒,也就是说网站在一秒以内能处理多少http(https/tcp)请求。与吞吐量对应的衡量网站性能的还有响应时间、并发数、QPS每秒查询率。并发
响应时间是一个系统最重要的指标之一,它的数值大小直接反应了系统的快慢。响应时间是指执行一个请求从开始到最后收到响应数据所花费的整体时间。app
并发数是指系统同时能处理的请求数量,这个也是反应了系统的负载能力。
每秒查询率(QPS)是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准,在因特网上,做为域名系统服务器的机器的性能常常用每秒查询率来衡量。对应fetches/sec,即每秒的响应请求数,也便是最大吞吐能力。
咱们以高速收费站为例子也许更直观一些,吞吐量就是一天以内经过的车辆数,响应时间就是车速,并发数就是高速上同时奔跑的汽车数。因而可知其实以上几个指标是有内在联系的。好比:响应时间缩短,在必定程度上能够提升吞吐量。
其实以上几个指标主要反映了两个概念:
1. 系统在单位时间以内能作多少事情
2. 系统作一件事情须要的时间
服务器级别增长网站吞吐量也是诸多措施中最容易而且是效果最好的,若是一个网站能经过增长少许的服务器来提升吞吐量,菜菜以为是应该优先采用的。毕竟一台服务器的费用相比较一个程序员费用来讲要低的多。可是有一个前提,就是你的服务器是系统的瓶颈,网站系统以后的其余系统并不是瓶颈。若是你的系统的瓶颈在DB或者其余服务,盲目的增长服务器并不能解决你的问题。
经过增长服务器来解决你的网站瓶颈,意味着你的网站须要作负载均衡,若是没有运维相关人员,你可能还得须要研究负载均衡的方案,好比LVS,Nginx,F5等。我曾经面试过不少入道不久的同窗,就提升吞吐量问题,若是没有回答上用负载均衡方案的基本都pass了,不要说别的,这个方案就是一个基础,就比如学习一个语言,你连最基本的语法都不会,我凭什么让你经过。有喷的同窗能够留言哦
当一个请求到达服务器而且正确的被服务器接收以后,最终执行这个请求的载体是一个线程。当一个线程被cpu载入执行其指令的时候,在同步的状态下,当前线程会阻塞在那里等待cpu结果,若是cpu执行的是比较慢的IO操做,线程会一直被阻塞闲置很长时间,这里的很长是对比cpu的速度而言,若是你想有一个直观的速度对比,能够去查看菜菜之前的文章:
当一个新的请求到来的时候,若是没有新的线程去领取这个任务并执行,要么会发生异常,要么建立新的线程。线程是一种很稀缺的资源,不可能无限制的建立。这种状况下咱们就要把线程这种资源充分利用起来,不要让线程停下来。这也是程序推荐采用异步的缘由,试想,一个线程不停的在工做,遇到比较慢的IO不会去等待结果,而是接着处理下一个请求,当IO的结果返回来获得通知的时候,线程再去取IO结果,岂不是能在相同时间内处理更多的请求。
还有一点,尽可能减小线程上下文在cpu的切换,由于线程上线文切换的成本也是比较大的,在线程切换的时候,cpu须要把当前线程的上下文信息记录下来用如下次调用的时候使用,而后把新线程的上下文信息载入而后执行。这个过程相对于cpu的执行速度而言,要慢不少。
不要拿Golang反驳以上观点,golang的协程虽然是用户级别比线程更小的载体,可是最终和Cpu进行交互的仍是线程。
在讲cpu级别以前,若是有必定的网络模型的基础,也许会好一些。这里大致阐述一下,现代操做系统都采用虚拟寻址的方式,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操做系统将虚拟空间分为两类:内核空间和用户空间。内核空间独立于用户空间,有访问受保护的内存空间、IO设备的权限(全部的用户空间共享)。用户空间就是咱们的应用程序运行的空间,其实用户空间并无操做各类IO设备的权限,像咱们平时读取一个文件,本质上是委托内核空间去执行读取指令的,内核空间读取到数据以后再把数据复制到程序运行的空间,最后应用程序再把数据返回调用方。
经过上图大致能够看出,内核会为每一个I/O设备维护一个buffer(同一个文件描述符读和写的buffer不一样),应用程序发出一个IO操做的指令其实经过了内核空间和用户空间两个部分,而且发生了数据的复制操做。这个过程其实主要包含两个步骤:
1. 用户进程发出操做指令并等待数据
2. 内核把数据返回给用户进程(buffer的复制操做)
根据这两个操做的不一样表现,因此IO模型有了同步阻塞,同步非阻塞,异步阻塞,异步非阻塞的概念,可是这里并不是此文的重点,因此不在展开详细介绍。
利用cpu提升系统吞吐量主要目标是提升单位时间内cpu运行的指令数,避免cpu作一些无用功:
cpu负责把buffer的数据copy到应用程序空间,应用程序再把数据返回给调用方,假如这个过程发生的是一次Socket操做,应用程序在获得IO返回数据以后,还须要网卡把数据返回给client端,这个过程又须要把刚刚获得的buffer数据再次经过内核发送至网卡,经过网络传送出去。因而可知cpu把buffer数据copy到应用程序空间这个过程彻底没有必要,在内核空间彻底能够把buffer数据直接传输至网卡,这也是零拷贝技术要解决的问题。具体的零拷贝技术在这里再也不展开。
至于网络传输级别,因为协议大部分是Tcp/ip,因此在协议传输方面优化的手段比较少,可是应用程序级别协议能够选择压缩率更好的,好比采用grpc会比单纯的http协议要好不少,http2 要比http 1.1要好不少。另一方面网卡尽可能加大传输速率,好比千兆网卡要比百兆网卡速度更快。因为网络传输比较偏底层,因此人工干预的切入点会少不少。
大部分程序员都是工做在应用层,针对应用级别代码能提升吞吐量的建议:
加大应用的进程数,增长并发数,特别在进程数是瓶颈的状况下
优化线程调用,尽可能池化。
应用的代码异步化,特别是异步非阻塞式编程对于提升吞吐量效果特别明显
充分利用多核cpu优点,实现并行编程。
减小每一个调用的响应时间,缩短调用链。例如经过加索引的方式来减小访问一次数据库的时间
但愿你们有所收获 --菜菜
恭喜 安浅 QI 两位喜提上周抽奖Golang书籍。
互联网之路,菜菜与君一同成长
长按识别二维码关注