一,问题排查
测试说,网站页面突然很卡。
首先kubernates集群没有报警,集群资源cpu,内存使用也还算正常。
然后查看jvm,发现并没有大量的full gc。确切的说,近期连一次full gc都没有发生。那么说明,不是pod问题,不是jvm的gc引起的。
再然后排查数据库连接,通过druid查看,发现sql也没有什么问题。
看起来一切都是这么安好。。。

转念一想,既然服务都如此正常,会不会是网络资源问题?
查看集群资源,网络连接情况。

记一次web请求量上不去的排查记录,及grpc client请求优化
发现tcp连接数在5000,按说呢这个量并不大。
但是奇怪的是,这个5000的瓶颈,这个拐点就很可疑。看起来是收到了限制。
经查,果然是slb设置了最大tcp连接数为5000,导致更多的请求进不来,导致的此次问题。
将该阈值改为5w,再次压测,问题解决。

二,根本原因处理
不过这只是解决了问题的表象,这么多time_wait tcp连接说明什么呢?
time_wait 说明client已经向服务端发送最后的关闭请求,自己等待2msl的过程中。
记一次web请求量上不去的排查记录,及grpc client请求优化
那么说明有大量的tcp短连接在关闭中。

回顾自己的应用,推测是由于大量的grpc连接造成的,那么需要对grpc client进行优化,将每次请求创建一个client,改为所有相同的请求使用同一个client后,tcp中time_wait数量,和inuse数量都大幅减少,从而解决该问题。

三,单例的grpc client是否会引起性能问题?
按说,grpc使用http2,而http2是支持多路复用的,这样说来或许不需要额外的连接池。
真的是这样吗?
通过压测,我发现单个连接的client可以支持最大到9w的qps,并发量再大,cpu占用率会上去,但吞吐量会下来。
为什么会这样的?
猜测大概是由于tcp头阻塞和client锁竞争引起的。
应用层的头阻塞:在http1.1时各个request和response需要排队进行,在没有收到response报文之前,该tcp不能被复用。
虽然http2避免了应用层的头阻塞,但依然存在tcp层的头阻塞。
tcp头阻塞:tcp在并发发包时,接收方可能会先收到后面的包,那么这个包就不能放到socket buf上,只能先放到内核协议栈上,这就是tcp头阻塞。

那么怎么解决呢?
一个成熟的方案是,池化。
通过使用自建连接池,经测qps可以达到40w左右。

总结,如果服务的并发量不高,使用单个client既可以避免大量的tcp TIME_WAIT问题,也可以支撑数万的qps。
当并发量远远超过这个数量级时,可以考虑使用池化方案进行优化。

滴滴在使用grpc时就使用了自建的连接池
具体的池化代码,我后续贴出。

相关文章:

  • 2021-05-03
  • 2021-09-29
  • 2021-11-17
  • 2022-12-23
  • 2021-11-02
  • 2022-02-14
  • 2022-12-23
  • 2022-01-23
猜你喜欢
  • 2021-11-04
  • 2022-12-23
  • 2022-01-13
  • 2022-12-23
  • 2021-06-16
  • 2021-10-21
  • 2021-05-18
相关资源
相似解决方案