举个栗子:一个系统,有个历史add接口,受最大数量限制,使用memcache和mongo。
V4.0.1之前逻辑:
- 从cache取全部数据
- 按最大数量限制对数组做增改逻辑
- 如果大于24小时,则写入mongo
- 写入cache
统计次数:
- cache取1
- cache写1
- mongo全量写1/24小时
大概流程图如下:
初步分析:该逻辑在最初是可以稳定运行的,因为数据量不大,但随着时间的推移,使用量的上升,memcache不止该接口在用,其他服务也会写入大量的数据,问题就逐渐显露出来了。
问题:随着使用时间的增加,memcache爆了,会释放低频数据(即使设置了30天有效期),然后用户的历史数据就变成了24小时之前的数据,造成上次同步到MongoDB后的时间节点开始的历史数据丢失情况发生。如果memcache挂了重启了,全部用户将丢失写入MongoDB前的全部数据。可用性不稳定,持久性堪忧。
于是有了V4.0.1版本。
该版本逻辑变更如下:
- 从cache删除全部数据
- MongoDB取出全部数据,按最大数量限制对数组做增改逻辑,update upsert全量数据更新到MongoDB
- 从MongoDB取全部数据
- 写入cache
统计次数:
- cache删1
- cache取1
- cache写1
- mongo 全量取2
- mongo 全量写1
大概流程图如下:
瓶颈点:MongoDB写压力增大,写频率高了之后,因为每次都是读写全量数据,数据变大后,可能触发MongoDB增加块和数据迁移,慢查询触发时间是3秒,只要网络传输或者MongoDB性能稍有问题,立马就是慢查询,影响业务。持久性保证了,然而性能和前一个版本相比,用脚趾头想也知道会下降不少,最关键的是,全部驻地公用一个中央MongoDB,性能上的问题迟早会显现出来,当然,这个版本之后,性能问题暴露后,用了MongoDB下沉的策略,将压力转嫁到了驻地本地的MongoDB,至此,该函数已经可以稳定提供服务,然而,这肯定不是最优解。
V5.0.0初版方案:
- MongoDB取next和下标可用数组:没有则一次性创建最大数量的初始化数据,加入当前Add数据写入MongoDB;有数据则直接执行增删改逻辑,按数组下标update更新MongoDB数组指定元素数据
- MongoDB取全部数据
- 过滤后将有效数据写入cache
统计次数:
- MongoDB取2 一次取next,一次取全量
- MongoDB写1
- cache写1
大概流程图如下:
分析说明:没有数据则一次性创建最大数量的初始化数据,避免了后续数据变大的情况造成的块增加和数据迁移的情况发生。之后再增记录,只对初始化好的数组子元素进行增改,避免了全量数据更新。以此降低了MongoDB的写入压力。该方案,主要是为了降低MongoDB层面压力,优化写入性能。
在测试同学打压的过程中,琢磨着还可以优化,毕竟全量读也很蠢,所以尝试调优逻辑,将MongoDB的压力分摊到cache上:
- 从cache取有效数据
如果没有有效数据,从MongoDB全量取一次,过滤处理得到有效数据,还没有就初始化有效数据为空 - MongoDB取next和下标可用数组:没有则一次性创建最大数量的初始化数据,加入当前Add数据写入MongoDB;有数据则直接执行增删改逻辑,按数组下标update更新MongoDB数组指定元素数据,返回新增的那条数据。
- cache对有效数据进行增加后写入cache
统计次数:
- cache取1
仅在不存在数据的情况,MongoDB取全量1 - MongoDB取next 1
- MongoDB写1
- cache写1
大概流程图如下:
对比分析:相对未优化版本,将MongoDB全量取的逻辑限制在cache取不到数据的情况下,减少了平时的MongoDB全量取。多了一步cache取。MongoDB增记录后返回增加的那条记录,叠加逻辑复用给cache,确保cache只保存有效数据。
最终版本优势总结:
通过代码层的逻辑调优,避免了MongoDB中的全量读写,大幅降低了MongoDB的压力。Cache层调优后,仅在Cache没数据的情况下回读MongoDB数据后处理完毕回写Cache。逻辑中仅MongoDB更新方式的变更,性能就比旧接口提升了40%。
核心思路:用第一次的空间占用换后续的时间和效率,杜绝全量大数组更新,将更新锁定到最小范围。尽可能减少瓶颈点(MongoDB)的读写。
回顾:如果最初的逻辑Cache层是持久可靠的,就没必要这么折腾了。比如用了Redis的话,第一种逻辑就差不多OK了,但每次的大数据量回写MongoDB还是会存在超时的可能。架构实现是在实际生产过程中逐步调优的,上面讲的只是一个不断优化的思路而已,道途漫漫,且行且看。
如您从本文得到了有价值的信息或帮助,请考虑扫描文末二维码捐赠和鼓励。
如本文对您有用,捐赠和留言 将是对我最好的支持~(捐赠可转为站内积分)
如愿意,请向朋友推荐本站,谢谢。
尊重他人劳动成果。转载请务必附上原文链接,我将感激不尽。