知识卡片

组合净值计算的分级批量优化

普通读书笔记卡

内容

雪球的组合净值计算面临一个规模问题:一支热门股票(如南车北车中车、暴风科技)可能同时出现在超过20万个投资组合里,理论上股价每3秒变化一次,涉及这支股票的所有组合就都要重新计算一次净值。这里有个容易被问到的问题——为什么不在用户请求时实时计算?答案是”组合净值”这个计算本身很复杂,除了股价变化,还要考虑分红送配、分股、送股、拆股、合股、现金、红利等一系列业务规则,开发初期计算逻辑经常需要调整,因此最初设计成了后台离线计算模式(当时正在改造成”分红送配逻辑离线计算、股价组成的净值实时计算”两部分合并输出的方案)。但离线计算本身的实现方式也存在低效之处——原来的实现是循环遍历所有组合,对每个组合单独获取所需的全部价值数据、再逐个计算,一轮循环结束后立即开始下一轮循环,这意味着同一支股票的价格会被反复独立查询很多次(因为它同时属于很多个组合)。优化方案有两条:一是分级,把活跃用户的活跃组合和其他组合区分开处理,让计算资源优先服务真正有人在看的组合;二是批量,先把当前所有股票的现价一次性拉取到本地存起来,形成一份”股价快照”,这一整轮的所有组合计算都共用这一份快照,而不是每算一个组合就单独查一次股价。这个优化的核心思路和[[预建索引替代扫描列表的性能优化]]是同一类模式的另一种体现:当同一份基础数据(这里是股价)会被大量重复的计算单元(这里是20万个组合)反复读取时,与其让每个计算单元各自独立获取数据,不如先统一拉取一份快照供所有计算单元共享,把”数据获取”这个开销从”每个计算单元一次”降低到”每一轮计算一次”。

参考来源

- 位置:《高可用架构(第1卷)》第1章《高可用架构案例精选》"1.5 雪球在股市风暴下的高可用架构改造分享"节,"1.5.3 雪球架构优化历程"(源文件:_epub-src/OEBPS/Text/Chapter1_5_4.xhtml) - 结论依据:原文说明"我们的计算逻辑是比较低效的:循环遍历所有的组合,对每个组合获取所有的价值数据,然后计算……优化如下所示:分级……批量:拉取当前所有股票的现价到存里,这一轮的所有组合计算都用这一份股价快照",直接支撑本卡片结论。 - 原始内容:实际上,我们的计算逻辑是比较低效的:循环遍历所有的组合,对每个组合获取所有的价值数据,然后计算。完成一遍循环后,立即开始下一轮循环。优化如下所示:分级:活跃用户的活跃组合和其他组合。批量:拉取当前所有股票的现价到存里,这一轮的所有组合计算都用这一份股价快照。