【技术】服务不断优化,性能不断翻倍

作者: | 更新日期:

我手上有一个服务,多年前已经优化过两次了,最近又优化了一次,性能再次提高一倍。

本文首发于公众号:天空的代码世界,微信号:tiankonguse

一、背景

我负责的一个资料聚合外加缓存的服务,数据维度有七十多个不同类型的数据,业务维度有接近两千多个,来源ip维度有六七千个,字段元数据维度也有六七千个。
当然,这里面还有一些架构设计的内部维度,这里就不提了。

面对这么多维度,经常有老板问或者与业务一起定位问题时题,如:
一个业务都拉取拉取哪些类型的数据了?
一个业务的来源ip有哪些?
一个业务都拉取哪些字段了?
一个字段都被哪些业务拉取了?
。。。

二、统计并不是那么简单

面对上面这些询问,我做了一个多维度统计服务。
这个服务实现特别简单,但是只有一个问题:量特别大。
仅仅是上面我提到的维度两两交叉计算,互不相同的元数据就有也有七千多万,算上内部维度则有上亿的元数据对。

当然,实际并不是完全的两两交叉的,比如一个来源ip一般只属于几个业务、一个业务只拉取部分字段等等。
这样算下来,实际互不相同的元数据对有几十万个。
另外我的上报机器有上百台,这样每秒收集一次元数据对。请求量则也有上百万甚至千万。

三、舍弃不需要的信息

如果需要统计每秒的元数据对的关系,每秒请求量至少是千万级别。
如果把时间粒度扩大到分钟级别,请求量则降低至几十万。

说干就干,我几天时间就做完了相关工作:上报服务进程内一级聚合、服务所在机器agent二级聚合、远程统计服务三级聚合。
发布上线的时候,发现访问量太大,mysql数据库根本扛不住这个量。

考虑到我这个服务仅仅需要两个维度的关系,并不需要访问量,为了降低数据库的压力,我选择以月为维度来统计数据了。

另外为了降低数据库的压力,我在proxy上做了一致性hash,这样可以保证相同的元数据对只出现在一个进程内,从而只写数据库一次。

四、解包很浪费性能

时间粒度调整到月为单位后,再次上线,发现访问量还是太大,服务proxy的CPU还是直接跑满了。

简单分析后,发现框架的proxy收到的每个包都需要解开,然后才能决定路由到哪里去。
这个解包的过程是很消耗性能的。
而解包的目的是为了获得一个hash值,从而决定把请求路由到哪个worker去。

这里做了一个优化:将协议中的hash值提取出来,放在数据包的定长位置去。
这样,proxy只需要几条指令即可获得hash值。
优化后,proxy的CPU降了下来。

五、为了目标,要有所放弃

将协议的hash值提取出来后,proxy的性能确实提高了。
但是此时worker成为瓶颈了,也是在打解包上消耗了大量时间(CPU将要跑满了)。

但是我们使用的是统一的协议,这个打解包是无法避免的。
最终为了能够上线服务,我开始着手分析统计的数据,发现大部分数据都是字段维度。
于是我调整策略,不再统计六七千个字段的相关关联数据。

这个调整效果很明显,服务上线后CPU一下降低都原来的三分之一。

六、通用协议是枷锁

上面提到,通过放弃字段关联维度,统计服务终于上线了。
那些都是两年前的事情了。

如今已是2019年了,依旧不断有业务询问有哪些业务在拉取某个字段。
于是我只能采取终极方案了:放弃通用协议。

放弃通用协议后则变得灵活多了。
自己设置一个私有的二进制协议,不管是获取hash值,或是打包(序列化)、或是解包(反序列化),都变得轻松高效。
这时,即使加上字段维度的统计,CPU 也没那么高了。而由于包更小了,proxy的处理量也更高了。

服务优化后,单机处理量到达3W/s完全没有问题。
按上面的CPU看,隔离部署后,单机我部署三个server,跑10W/s也不成问题。

七、枷锁无处不在

上面通过抛弃通用协议这个枷锁提高了性能,但是可以发现proxy的CPU依旧偏高。
想充分利用这台机器的话,需要部署三个server才行。

proxy是干什么的呢?
答案很简单,proxy是网络框架用于管理收发请求包的公共程序。

那我们想进一步提高性能,只好抛弃proxy或者抛弃这个网络框架了。

另外,这个代码目前是使用c++98编译的,其实c++11对很多库的实现都做了很多优化,如果我们放弃旧编译器,使用更高的编译器,性能也会提升一个阶级。

枷锁无处不在,有些可以抛弃,有些却只能慢慢等待,随着大趋势去淘汰枷锁、抛弃枷锁。
而这里每做一次优化,其实都是在放弃某些通用的东西。

八、最后

服务优化就是这样,遇到最消耗性能的地方,通过放弃一些东西来解决问题。
然后再次找到最消耗性能的地方,再放弃一些东西来解决。
而最终,剩下的都不能放弃式,那能优化的地方就不多了。

另外,我这里优化的重点是协议的两次优化,而协议其实是一个很有趣的话题。
很多工作多年的人,有时候聊起来协议的细节,很多都不清楚,甚至知道的是错的。
两年前我曾写过《什么是协议》,建议想了解这个话题的朋友,一个一个字的看完。
当然我知道,即使你打开,也是快速滑到底部了或者看几句直接关掉,大部分人都是如此。

-EOF-

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越