Swoole性能优化和压测结果分享

大家好,在v5.1.0到v5.1.4这几个版本中,Swoole 官方开发团队对 HTTP 服务器进行了大量性能优化,性能得到了巨大的提升。于是趁这个机会跟大家简单汇报一下成果:blush:

为什么要优化

其实在TechEmpower的几次压测中,Swoole并没有取得令人特别满意的成绩。因此从去年开始,我们断断续续花了很久的时间对Swoole做了一些优化。

优化的成果

因为TechEmpower换了特别好的服务器作为新的压测环境,所有框架的压测结果比以往好了很多倍。详细可以看看这个issue。历史成绩之间差距变大了,所以这里采用Swoole的排名变化作为优化结果。


未优化前在TechEmpower Round 21的测试中,Swoole在PHP框架中排名第7可以点击这里看看详情


优化后在TechEmpower最近的一周一测中,Swoole在PHP框架中排名第2可以点击这里看看详情

可以看到经过优化后的Swoole的压测性能比以往优秀了不少,感兴趣的朋友可以访问这个网站看看最近的压测信息。

性能瓶颈

我们一开始通过perf和wrk生成了程序执行的火焰图,旨在分析出Swoole在作为HTTP服务器的过程中执行函数的耗时情况。并且总结出了一些问题:

  1. 同一个连接发来的多个请求,Swoole总会重复获取客户端ip。
  2. Swoole\Http\Resquest::server属性默认初始大小为8会导致一次数组扩容和内存拷贝。
  3. 每个不同的请求,它们的Swoole\Http\Resquest或者Swoole\Http\Response中,有些数组或者属性里面的key都是一样的,区别在于value不一样。但是我们却会为每个key单独申请内存。
  4. 初始化或者读取Swoole\Http\Resquest和Swoole\Http\Response的属性的过程中,ZEND_API提供的函数太过繁琐。
  5. 有些遗留的析构函数并没有去掉,在整个生命周期中还在执行。
  6. 压测的代码没法发挥Swoole的性能。

解决方案

针对问题1,我们的思路是,如果客户端ip是本地回环地址127.0.0.1,直接将这个ip地址写入数组中。如果不是,通过缓存的形式,将客户端ip缓存起来。减少ip的获取次数。

针对问题2,我们计算过,server属性只有10个,初始化数组的过程中直接设置数组大小为16,解决数组扩容和内存拷贝。

针对问题3,我们将相同的,只读的数组key名作为关键字符串,让它们的生命周期变成永久的。所有的请求共用相同的key。减少内存的申请和释放。

针对问题4,我们知道,php的对象实例化后,其内部的属性保存在一个柔性数组中,也就是属性的在结构体中的位置是固定的,读写属性的时候根据zend_class_entry先获取属性的偏移量,这样可以从对象的柔性数组中获取对应的属性。再加上Swoole的内置类的属性在初始化的时候只有简单的赋值操作,而且属性一定存在并且没有动态属性。所以可以直接通过指针操作对象的zval,而不通过ZEND_API操作。

针对问题5,把没用的析构函数删了就行。

针对问题6,我们按照TechEmpower的压测规范,重新设计了压测代码,将压测环境的容器由php:8.3-cli换成ubuntu24.04。

经过在上面的几步操作,Plaintext和 JSON serialization的成绩已经相当可观了,然后在优化Single query,Multiple queries,Fortunes和Data updates过程中我们发现,php的各个网络引擎或者框架都是通过pdo扩展进行数据库操作,所以在这个阶段的成绩都差不多。那么在pdo这边做优化就不太现实了,因此我们转换了以下的思路:

Swoole在发送数据的时候,如果响应体大于4k,也就是一页,响应头和响应体会直接经过两次套接字发送。否则就将响应体拼接在响应头后面,经过一次套接字发送。这里设计是因为系统调用时间比内存复制会快。但是我们认为这里的话4k还是有点偏小了,需要找到一个的合适的值。

于是我们经过8k,16k,32k和64k的测试,我们发现在数据小于16k的时候,响应体拼接在响应头后面通过一次套接字发送出去效果会更好,否则就需要分两次发送。但是有意思的是,这个优化对于像Data updates这种有多次数据库IO和返回大数据的情况下,能提高的性能可能就几百左右,因为这个阶段数据库IO反而占了性能问题的大头。

结束语

很感谢大家能看到这里,以上都是比较简略的说明,以后有时间会写详细的优化过程,未来也会着手对协程或者SWOOLE_PROCESS模式等等的优化工作。也很感谢大家对Swoole的支持和鼓励,祝愿大家在未来的日子里身体健康,工作顺利,万事如意。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 7

看不懂,但有点担心会不会类似车辆碰撞测试之后的那种针对测试成绩的专项优化,而非通用优化

3天前 评论
加了sugar (楼主) 3天前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!