2012/05/20

MySQL 迁移到 Redis 记

请甄别文章的时效性。

这篇文章最后更新于 10 年前 ,其中所记录的信息可能已经不再合理或有效。如有任何建议,欢迎与我联系

前些日子,一个悠闲又不悠闲的下午,我还在用 Node.js 写着某个移动互联网应用的 API 服务端。那时还是用 MySQL 作为数据库,一切都很好,所有功能正常运行。可是有很多问题让人不安:

  1. 频繁的产品功能变化让 MySQL 跟不上 产品初期功能变化很频繁,其中很多变化都不得不对数据库结构做出更改。对于 MySQL 来说,也许是改一个字段名方便 SELECT,也许是把一个字段移到另一个表方便索引,也许是要对多个表重新设计来达到修改要求(这种情况最惨烈,但开发过程中遇到过不止一次)。

  2. 符合范式的设计让 JOIN 在 SELECT 语句中大行其道

    尽管在设计时已经做好规划,保证在多数查询时不会用到 JOIN,但是在其它不少地方仍然很难回避两表甚至多表联查,一些模块中 SQL 语句的复杂度甚至能达到大学数据库原理考试时考查的 SQL 语句题目的水平。写起来烦,想想实际运行情况,也不禁为 MySQL 同学捏一把汗。于是后来对复杂的 MySQL 语句增加了 Cache,Redis 第一次在这个项目登场就是干这个的,当时 Cache 的设计思路是:

    Redis 存储两份数据,一份是数据缓存,一份是数据的最新版本号,执行复杂 SQL 查询时先检查这个查询在 Redis 里有没有数据缓存且对比数据的最新的版本号看当前数据缓存是不是最新的,是的话就读出来直接返回,不是的话查询 MySQL 得出结果并保存在 Redis 数据缓存中。如果更新了会影响这个查询结果的数据的话则简单地将 Redis 里该数据的最新版本号加 1 即可。

    这个设计很简单实用,但很快问题就暴露出来了:因为缓存的加入导致整个系统更复杂,而且随着 MySQL 数据库结构的不断复杂,单纯加入缓存无法根本上解决这一问题。更重要的是,由于读写频率基本保持在 1:1,导致缓存命中率极低,不如不用。

  3. 一切问题的解决方案都是 NoSQL 上述问题让我重新考虑是否用 NoSQL 替换 MySQL。关于 NoSQL 数据库我接触过的为 MongoDB 和 Redis,最后选择 Redis 的原因是因为系统中已经使用了 Redis 做 Cache,对 Redis 了解更多。

    现在的 API 服务端代码已经从 Node.js(JavaScript) + C + MySQL 迁移到 Node.js(CoffeeScript) + C + Redis。通过实践,使用 Redis 后的代码更易维护,更加整洁,性能也更高。同时在迁移时写了一个简单的 Redis ORM 模块,用起来十分方便。