来源 14年11月第5题第3问
分值(8分)
为进一步提高数据库访问效率,项目组决定在中间层与数据层之间引入缓存机制。赵工开始提出可直接使用MySQL的查询缓存(query cache)机制,但项目组经过分析好友动态显示等典型业务的操作需求,同时考虑已引入的数据库扩展机制,认为查询缓存尚不能很好地提升系统的查询操作效率,项目组最终决定在中间层与数据层之间引入Memcached分布式缓存机制。
(a)请补充下述关于引入Memcached后系统访问数据库的基本过程:系统需要读取后台数据时,先检查数据是否存在于(1)中,若存在则直接从其中读取,若不存在则从(2)中读取并保存在(3)中;当(4)中数据发生更新时,需要将更新后的内容同步到(5)实例中。(备选答案:数据库、Memcached缓存)
(b)请结合已知信息从缓存架构、缓存有效性及缓存数据类型等方面分析使用Memcached代替数据库查询缓存的原因。
参考解析
在Web系统架构优化中,缓存机制是缓解数据库压力、提升响应速度的关键措施。本案例中,项目组在中间层与数据库之间引入了Memcached分布式缓存,而不是依赖MySQL自带的查询缓存。
首先来看缓存的基本访问流程:当系统需要读取数据时,先检查Memcached缓存中是否已有数据,如果有则直接返回,避免访问数据库;如果没有,则访问数据库获取,并将结果写入缓存,供下次快速访问。当数据库中的数据发生更新时,必须同步更新缓存中的副本,确保数据一致性。这个流程显著减少了数据库的直接访问次数,从而降低了磁盘I/O压力。
对比MySQL查询缓存与Memcached:
缓存架构方面:MySQL查询缓存属于数据库内部机制,只在单个数据库实例内生效,无法跨节点共享;而Memcached是独立的分布式缓存服务,可以部署在多台服务器上,具备良好的扩展性,非常适合互联网级高并发场景。
缓存有效性方面:MySQL查询缓存一旦表发生更新,与该表相关的所有缓存查询结果都会被清空,导致缓存命中率低;而Memcached采用灵活的过期时间与手动更新机制,可以根据业务特性精细化地管理缓存数据,使缓存利用率更高。
缓存数据类型方面:MySQL查询缓存仅缓存SQL语句的结果集,局限性大,不能满足复杂业务;Memcached以键值对方式存储数据,可以缓存对象、JSON、序列化数据等,特别适合社交网络中复杂多样的数据访问场景,如好友动态流、用户信息缓存等。
Memcached能够为本系统提供更高效、更灵活、更可扩展的缓存服务,在性能和适用性上远优于MySQL的查询缓存。
核心对比:MySQL查询缓存 vs Memcached
| 特性 | MySQL查询缓存 | Memcached |
|---|---|---|
| 缓存粒度 | 粗,以整个SQL语句和结果集为单位。 | 细,以单一的键值对为单位。 |
| 缓存位置 | 在MySQL数据库进程内部。 | 独立的、分布式的内存缓存服务器。 |
| 失效机制 | 被动,任何相关表的写操作(INSERT/UPDATE/DELETE)都会使所有涉及该表的查询缓存失效。 | 主动,由应用逻辑控制,可精确设置过期时间或手动删除。 |
| 灵活性 | 低,只能缓存完整的SQL查询结果。无法缓存部分数据或计算结果。 | 高,可以缓存任何可序列化的数据(对象、Session、页面片段、计算结果等)。 |
| 扩展性 | 无,仅限于单机MySQL实例。 | 高,支持分布式集群,可以水平扩展。 |
| 适用场景 | 读多写少的静态表(如配置表、地区表)。 | 高并发、动态的任意数据缓存,缓解数据库读写压力。 |
深入解析与结论
1. MySQL查询缓存:为何被弃用?
MySQL查询缓存的设计存在一个致命弱点:它的失效策略过于粗暴 。一旦某个表发生任何微小的改动,所有与该表相关的查询缓存都会被全部清空。在写操作频繁 的现代应用中,这会导致缓存命中率极低,维护缓存本身反而带来了巨大的性能开销。正因如此,在MySQL 5.7中查询缓存是默认关闭的,并在MySQL 8.0中被彻底移除。
2. Memcached(及Redis):现代应用的标配
Memcached作为一个独立的分布式内存键值存储,它将缓存与数据库解耦。这种架构带来了巨大优势:
- 精准控制:应用程序可以完全控制缓存什么数据、缓存多久、以及何时使其失效。
- 高性能与高扩展性:独立的缓存层不会影响数据库的性能,并且可以通过添加节点轻松实现水平扩展,以应对极高的并发请求。
- 通用性:它不仅限于缓存数据库查询结果,几乎可以用于任何需要加速的场景。
结论:
对于当今绝大多数业务场景,Memcached(或其更强大的替代者Redis)是远比MySQL查询缓存更优的选择。它提供了更精细的控制、更高的灵活性、卓越的扩展性和更稳定的性能,能够有效构建一个独立于数据库的高性能缓存层。MySQL查询缓存由于其固有的设计缺陷,已经退出了历史舞台。