延迟与吞吐

来源:互联网 发布:数据库系统基础教程 编辑:程序博客网 时间:2024/04/30 18:27

对于一个request-response类型的在线服务来说,延迟和吞吐量是至关重要的性能指标。

延迟:从客户端来看,就是从发送请求到接收响应的整体耗时,包括:请求的网络耗时,请求在服务端的处理耗时以及响应的网络耗时。

吞吐量:服务在一定的并发下,每秒可以处理的请求数。

延迟和吞吐天生是矛盾的。对于服务来说,请求的处理是一个排队系统,且排队可能发生在请求路径上的任何环节,比如:请求的TCP包在路由器排队或者是在服务器的接收缓冲区等等。当吞吐量增加,那么必然会导致同一时间请求并发的增加。由于资源的限制,同一时刻可以处理的请求数是固定的,取决于整个请求处理过程中最小的那个环节。当并发请求数大于这个值时,就会有请求排队等待被处理。所以,要提升服务的吞吐量,必定会增加整体延迟。另外,如果服务的延迟(单个请求的耗时)减少,由于排队的请求的等待时间也减少了,所以吞吐量会上升。

假设一个单线程的服务,单个请求的耗时是10ms(在服务内部计算的耗时,包括从请求解析到处理完毕),那么该服务的吞吐量最大值是100req/s。而当在10并发下,由于该服务同时只能处理一个请求,所以并发请求的等待时间会加长,整体服务的延迟会大幅增加。如果只并发发送10个请求,不考虑其他因素,由于服务单线程串行执行,那么整体耗时是100ms,第一个处理完的请求耗时10ms,第二个20ms,第三个30ms,……,整体延迟是55ms。这种情况下,将请求耗时10ms减少为8ms,整体延迟也减为44ms。当然,上述近似计算没有考虑复杂的因素,但是基本上可以表示这种趋势。所以优化服务请求耗时,可以一定程度上,减少延迟,并增加吞吐。

绝大多数的服务需要请求其他数据源或者另一些服务,是通过网络调用的方式实现的。通常情况下,服务端程序的网络IO模型是基于多路复用的,会有IO线程池处理IO事件,专门的业务线程池处理每个请求。对于请求处理中,基本上都是同步请求后端服务。即在通过网络IO请求后端时,当前的业务线程会一直阻塞,直到接收到响应。那么,再等待网络IO时,线程资源是浪费的,产生了不必要的上下文切换。通过将客户端请求进行IO异步化,可以提升资源利用率,类似的机制在ngx-lua中已经实现。当请求后端服务时,首先将请求序列化为字节数组,然后写入请求buffer,并将对应的fd添加到事件循环中,当该IO返回后会回调对应的处理函数。这种异步的处理方式,在同时请求多个后端服务时,代码写起来会比较别扭,可以基于java的future进行改造,实现同步的代码书写方式。简单总结下,通过此种IO异步化的方式实现客户端,可以在相同资源的情况下,实现更高的吞吐量。

原创粉丝点击