缓存的不当使用案例分析

1、背景 redis

      最近一朋友作社区重构,社区主要功能有发帖、回帖、查看帖子详情,详情页按不一样条件展现回帖(除了预先定义的顺序外,可能每一个用户看到的顺序都不同,组合超过100个),大概的效果以下: sql

之前用的是开源的代码,存储用的是Mysql,系统也过于臃肿,稍微有点流量系统响应就很慢,因此准备重构。数据库

重构后的方案以下后端

一、存储仍是Mysql;缓存

二、为了提升访问速度,引入MongoDB做为缓存(为何不用Redis,由于MongoDB多线程,可扩充性好,而且支持较复杂的查询) 多线程

Mysql数据表大概以下:
image.png运维

    上述表格是通过简化版的内容。spa

    存储方面,Mysql存了全量的帖子和帖子回复,MongoDB也存了全量的帖子和帖子回复,之因此这么设计是由于让用户帖子详情页不用访问数据库,提升访问速度。线程

     那为何只保存在MongoDB里呢,由于MongoDB不支持多表事务,社区的场景插入回复,还有其它逻辑须要处理,因此须要借助Mysql的InnoDB的事务机制保证数据的一致性。设计

    重构后访问帖子详情页顺序以下:

    一、根据帖子id从MongoDB获取帖子详情信息,包括标题、内容及发帖时间和发帖人,若是读取不到,直接报错;

    二、根据帖子id及当前条件从MongoDB获取帖子回复信息,一样读取不到也报错。

     为何不按分页将每一个帖子按页缓存回复呢,由于前面说了整个详情页展现条件很是复杂,能够倒序排,也可升序排,还能够只看做者,有的回复还有权限,若是所有缓存帖子回复列表,则缓存的数据量很是的大。

2、问题分析

      通过分析,这样的设计带来几个问题:

     一、系统设计比较复杂,由于要保证数据在Mysql、MongoDB中一致,须要作不少的代码进行数据核对、检查;

     二、系统可用性差,由于帖子详情页所有读取的是MongoDB,因此若是MongoDB挂了,则整个系统也就挂了,特别是MongoDB对于运维团队还不是特别熟悉的状况下。

    有什么更好的方案呢,回到缓存的本质,关于缓存的使用有很多模式,通常来讲对缓存不要强依赖,即缓存挂了,整个系统不要挂,让系统打到后端存储而且更新缓存,这样还有最后一道防线,而在这个案例中,将MongoDB当存储用了,而且同时使用两个存储。

     若是当缓存用,怎么解决帖子详情页多种组合条件的致使缓存数据太大的问题?其实对于社区这样的场景,主要占内存的是回复的内容,只要保证帖子回复内容只缓存一份就能够了。

    改进后帖子详情页逻辑以下:

    一、根据帖子id从 MongoDB中获取帖子详情信息,若是获取不到,则从Mysql中获取,而且写回到MongoDB中;

    二、根据帖子id从MongoDB中获取当页须要展现的帖子回复id,读取不到再从Mysql回源,并写回到MongoDB中;根据上面获取的回复id再从MongoDB中获取回复的详情,一样若是获取不到则从Mysql回源,而且写入到MongoDB中。

    固然在添加、更新回复后,也须要更新相应的回复内容,这样就保证了帖子回复只缓存一份,不会形成缓存的数据量过大的问题。还有很是重要的一点,整个系统没有对缓存强依赖,即便MongoDB挂了,系统还会从Mysql读取数据。最后系统的代码也变得很是简洁。

    固然这里还有不少细节须要注意,像如何避免同一时间大量的回源Mysql的问题,这些业内已经有标准的方案,就不在此展开讨论了。

3、案例总结

一、系统设计越简单越好;

二、不要强依赖缓存;

广告联盟设计踩坑

从一次线上故障来看redis删除机制

全球智能DNS解析实践

相关文章
相关标签/搜索