概述:
笔者近期接受一个大数据项目的性能优化,为期两周,2.6万/s的日志处理速度提升至需求目标值5万/s。从整理项目流程阅读代码到性能优化目标实现,整个过程颇多波折。准备记录其间的技术性问题以做总结,希望可以对大家有所助益。
part1、你以为的真的是你以为的么---redis数据过期策略
项目接手时,项目研发人员X告知的信息,是模块A的实现kafka单一消费者性能不足(其实模块A的原本所需的数据量仅7000/s,后续哭诉之~),将kafka消费及对应处理流程改为多线程抑或多进程方可解决问题。浏览代码,大致的数据流是读取kafka数据--->过滤--->写入snappy。
ok,改一版多线程还是比较easy的。项目所用kafka topic对应的partition数量是8,众所周知,kafka partition和消费者的关系是一个partition只能由一个消费者进行消费,而一个消费者可以消费多个partition。鉴于目标是确认性能问题点,便将单线程版本改为8线程,每个线程处理一个固定partition的数量。然并卵,性能并没有提升。显然问题不在此处。
怎么办呢?看代码呗。数据流kafka数据--->过滤--->阻塞队列--->写入snappy,在多线程的实现过程中kafka数据--->过滤--->阻塞队列部分均已处理,那么剩下的就只能是snappy写入速度了。询问X得知由于项目周期紧,并未对snappy的性能进行过测试。好吧,测试走起。在测试环境中进行基准测试,按照原代码中2000条每次批量写入的方式,发现单线程写入每次的耗时约150-200ms。所以保守估计可以支撑8000/s。如此看来snappy也并未达到瓶颈,奇了个怪...
再次询问,性能问题是怎么判断出现在模块A?
场景还原:
正常数据流:读取kafka数据--->过滤--->写入snappy(snappy数据过期时间为5分钟)
为验证效率,另开一条数据流,读取kafka数据--->过滤--->redis(redis过期时间为2分钟)
现象:从snappy中查询到最近两分钟的数据量约7-8万
从redis查询数据总量大约为13万。
为看效果,将二者合一,读取kafka数据--->过滤之后分了数据流分开,相同的数据一份写入snappy,一份写入redis。结果依然是相同现象,没有性能问题,那相同的数据不同的结果为什么会有如此怪异的表现呢?
那么问题来了,这样的验证方式可靠么?
看一下redis官网的数据过期清除机制:
如上图,redis的过期数据并不会实时全部删除,而是按照采样删除策略进行的。看一下redis中文网的翻译吧:
(ps:有兴趣的小伙伴对应中英文翻译一下,有木有发现中文版最后的翻译有bug?-_-)
真相大白:验证方式不可靠。其实模块A当前数据量级下并没有原以为的性能问题。只是因为redis过期策略被误以为是过期便删除而导致。