这是我在 2016 OpenResty 全球技术大会上面的分享,起了一个 惊悚 的标题,内容是我自己工作多年的总结。这篇文章是现场分享的文字版本,欢迎大家评论。
说到高性能服务端,没有真正接触的工程师都觉得有些神秘,高不可攀的样子。而事实是什么呢?这里我结合自己接触到的一些讲讲。
大部分性能测试都是错的
这是第一个惊人真相。性能测试对于服务端是肯定需要做的,但真相是 90% 以上的性能测试都是错的,我自己接触到的性能测试基本没有做对的。为什么会这样?
第一点是性能测试方案没有业务处理链和大局观,很多都是拍脑袋得出来的。在做测试之前,参与测试的工程师是否对整个业务系统了然于胸?是否熟悉系统架构以及设计的原因?测试数据应该随机生成,还是需要从线上系统拷贝流量回来放大重放?可能出现性能的子系统和 API 是什么?
很多时候,都是开发列出几个 API,QA 找两台机器就开始随机发包了。美其名曰快速迭代。没有一个精心设计的测试方案,后面的都是无用功。
第二点是系统环境没有调优。我不止一次在邮件列表里面看到工程师的提问,为什么 OpenResty 的 hello world 性能测试数据这么低?其实只需要调整几个系统参数就可以解决。在一个 ulimit 还是 1024 的系统,不管什么语言开发的 web server,QPS 都很低。
第三点是没有检查系统和应用的错误日志。在做性能测试之前,你应该保证冒烟测试是通过的,而不是被 SELinux 拦截、连不上数据库等磕绊,让性能测试变成错误日志刷新测试。
第四点是没有用工具打满负载。如果 A 系统和 B 系统的 QPS 一样,但是前者 CPU 占用 30%,后者占用 90%,那么这个结果是没有意义的。
所以我们应该用能够产生足够大压力的测试工具,比如 wrk,来保证 A 系统和 B 系统测试时都被狠狠的打满 CPU。当然有些代码很差劲的系统,会使用阻塞 IO,无论如何 CPU 都很空闲,那时候需要拿起 off-cpu 火焰图分析工具照一照。
第五点是没有 APM 或者火焰图这样的分析工具。测试到性能问题,然后就没有然后了。只能丢给开发查问题,然后再测试新版本。这样的压力测试是没有意义的。我们应该使用科学的分析工具, 让数据替代猜测,很多性能点是完全猜测不出来的。
人类和动物最大的区别是,人类会创造和使用工具。
第六点是没有业务增长的预判。现在的系统性能可以支撑多少用户量,我们是否需要进行性能优化,甚至系统重构来应对未来的业务增长?其实做性能测试的工程师很多时候是不关心这个问题的。
上面提到的工具类和系统优化类的,这里有一个例子给大家参考: https://github.com/iresty/Mio/blob/master/benchmark.md
高大上系统的 QPS 并不高
现在参加技术会议,有一个感觉,大家产品的日访问量都是百亿起步,日志量都到了万亿,服务器集群几千几万的。听得时候心情澎湃,看看自家的产品实在是自惭形秽。
但是他们好像从来也不提这些高大上系统的单机 QPS 是多少?
让我们算一笔帐。某个产品,⽇活 2000 万,每个⽤户每天 500 个请求,那么每天就是 100 亿的访问量。你也可以当做日活 5000 万, 200 个请求,也是 100 亿。其实日活几千万的产品并不多,那些后台没事乱搞的 app 不算。
每天按照十小时计算,这样系统的 QPS 是:每天100亿访问量 / 每天10⼩时 / 3600秒 = 27.78 万,就按照 30 万算吧。那么单机 QPS 就是 30 万除以服务器数。那么问题来了,对于日活好几千万的高大上系统,如果单机 QPS 达到 3 万,只需要 10 台机器,如果 QPS 是 3千,就需要 100 台机器。
日志量的话,每天 100 亿,坚持一年就是 3.65 万亿,只要你的储存空间足够。真正的问题是储存万亿级别的日志,和存储百亿级别的日志,对于业务是否有质的改变?
很多人可能会说,我们的业务逻辑很复杂,所以 QPS 并没有预期的那么高。其实,机器比人便宜,多买 100 台机器,就几百万,用好几年,比招几个大牛要划算。这算是一个很痛的领悟。
系统性能和语言性能无关
有些架构师做系统技术选型时,主要精力放在开发语言的对比和纠结上,这是一个误区。对于高性能服务端来说,整个系统的性能瓶颈并不在语言,而在网络和数据库。
更重要的是,主流开发语言已经同质化。比如 JIT、协程 逐渐成为标配,虽然有些开发语言官方版本没有接受,但第三方版本已经很成熟。连 await/async 这些关键字在 C#、python、ES7 里面都是一样的,虽然有些语言的实现只是语法糖。在这个背景下,几千的 QPS 已经不成问题,如果你有 100 台机器,一样可以支撑日访问量 100 亿次的系统。
更重要的是,选择的这个开发语言,要开发、维护和替换成本低。这个如人饮水,冷暖自知,不要为了追时髦而使用某个新技术。
存在银弹
银弹,是三十年前提出的一个理论:在十年后不会出现让软件过程提高十倍的技术。现在软件过程上面都没有银弹。那么在高性能服务端开发上面有没有银弹呢?
我觉得是有的。在揭晓这个银弹之前,让我们先完成 极致性能 这个小目标。对于服务端的工程师来说,几千的 QPS 完全不能昭显技术的优势,对于性能的追求是没有极限的。
我们先看下经典的服务端架构,http request 到服务端的 web server,再转给业务逻辑,然后是缓存和数据库。这个过程会经过多个进程,也可能跨过多个服务器和机房。那么又没有一个技术方案, 可以把这个过程简化到一步呢 ?就是在一台服务器,一个进程内,处理完所有之前(web server + 业务逻辑 + cache + db)的事情呢?没有进程的通信,没有网络和磁盘的IO。
这看上去是一个不可能的事情。而实际上,早在 2010 年就已经实现了。 https://github.com/ecug/con-2012/tree/master/charlespeng 这是 2012 年的一个幻灯片,我当年部门的老大做的分享。
我们 当时的系统每天有接近 100 亿次用户请求,而服务器只有 10 台 ,分布在 2 个机房。所以我刚才提到的 QPS 计算,其实是一个真实的高性能服务端案例,是在资源有限的情况下,被倒逼实现的一个技术方案。由于高度优化,所以和业务绑定很死,没有开源出来。但是思路是可以借鉴的。
再回到银弹的话题,这枚银弹除了自带极致性能,还应该可以用 DSL 解耦开发和业务。春哥经常提到一个他在淘宝的亲身经历,在开发看来就是桃花源。就是产品同学有需求变更的时候,只用更新一个语法严谨的文档,编译器自动生成逻辑代码。
在这个桃花源里,不用不停的更新流程图,也不用为产品需求和技术实现不同而撕逼。工程师的重心是理解业务,设计好符合业务的 DSL,并进行针对性优化。
而业务小语言正是 OpenResty 2017 年的开发重点,春哥的分享会重点讲这个事情。我很期待在未来两三年的时间内,OpenResty 可以成为我所说的这枚银弹!这需要 OpenResty 社区的努力,也需要各位的贡献,多谢。
点击『阅读原文』,查看这个分享的幻灯片。