某天,二狗子写了一个 RPC 框架后,简单测了一下性能,发现超出 grpc 一大截。二狗子一高兴,忍不住找同事吹了一波。结果,同事亲测后对二狗子说框架性能也就这样。二狗子表示不服,跟同事一番唇枪舌剑后才发现,两个人测试方法有点不大一样。先不论测试方法不同在哪里,今天二狗子先来聊聊,对 RPC 框架做性能测试要注意什么。
一般情况下,必要且重要的指标有:吞吐率 (tps)、平均耗时、最大耗时、中位数耗时和 p99 耗时。通常情况下,二狗子不会记录 CPU 和内存的消耗,因为这两者的数值会一直变化,测试时并不好记录。
衡量一个 RPC 框架的性能需要从两个视角去思考:Client 视角与 Server 视角。只要消息协议、传输协议相同,同一种语言的实现就可以有好多种。在大规模的业务架构中,上游 Client 不见得使用的也是下游的框架,而开发者调用的下游服务也同样如此。
如果 Client 和 Server 部署在同一台机器上,且未绑定核,则测试时两端会互相影响。如果要压测 Server,那么我们应该给 Client 足够多的资源,这样才能把 Server 压到极致。
这个很好理解,如果外部因素影响过大,则无法测试 RPC 性能的优劣。
一般在测试时,会把 Server 和 Client 放在同一台机器上,这样可以减少网络的影响。如果网络影响过大,则主要耗时在网络传输上,无法测试 RPC 性能好坏。这里需要注意上面提到的第二点,部署在同一台机器上的时候需要为进程绑核数。
Server 和 Client 在同一台机器上的情况,Client 请求 Server 是不需要经过网卡转发的,这与实际情况不同,有需要的同学可以分开部署再进行压测一次。但是根据其它框架的压测结果来看,性能表现差距不大。
有一些测试程序非常简单,简单到只是客户端发送了一段“hello world”字符串,服务端直接把字符串原封不动地返回给客户端。这样测试出来的结果是不可信的,因为真实场景不可能这么简单。仔细想想,这样并不是在测试框架的性能,而是在测试你的框架读/写 socket 的速度。
RPC 业务特征是 Handler 逻辑较重,耗时较长,显然是不能串行处理的。因此 RPC 场景,Handler 必须要异步处理,上下文切换、I/O 协作等都是必须考虑的代价。
一次 RPC 调用往往需要多个微服务协作完成,而下游服务又会有其自身依赖,所以整个调用链路会是一个复杂的网状结构。测试的时候,具体这样做:
1. 我们在 Server 内用 Client 访问下游 Server,这能考察 Server 和 Client 的综合表现
2. 一个 Client 访问多个 Server,这能考察负载均衡是否足够并发,真实场景中很少一个 Client 只访问一个 Server
真实的请求中肯定会有长尾。对于在同一个线程里的请求,如果前面的请求慢了一下,那也只能跟着慢了,所以 1% 的长尾会影响远超 1% 的请求。
模拟长尾请求的方法有很多,最简单的就是在服务器端增加故意引发延迟的代码来模拟长尾请求。比如在服务端随机增加一个延迟等待的时间,在一定概率下增加延迟并使请求变为长尾请求。
如果有需要,可以对大包和小包分开测试。
对于 HTTP 框架来说,数据可以放在 query、path、header、body 等地方,不同位置对解析造成的影响也不一样。
需要考虑以下几点: