迁移系统时, 有时你必须建立一个小脚手架. 我们最近不得不这样做: 在 Instagram 上, 于遗留原因, 我们需要将大约 3 亿张照片映射到创建它们的用户的 ID, 以便了解要查询的分片(请参阅有关 我们的 更多信息) 分片设置 ). 虽然所有客户端和 API 应用程序都已更新并向我们返回 完整信息, 但仍有许多人缓存的旧数据. 我们需要一个解决方案:
1. 查找键并快速返回值
2. 将数据存在内存中, 理想情况下是在 EC2 高内存类型 (17GB 或 34GB, 而不是 68GB 实例类型) 中
3. 兼容我们现有的基础结构
4. 持久化, 以便在服务器宕机时我们不必重跑
这个问题的一个简单解决方案是将它们简单地存储在数据库行中, 其中包含 "Media ID" 和 "User ID" 列. 但是, 考虑到这些 ID 从未更新(仅插入),SQL 数据库似乎是多余的. 不需要事务, 也和其他表没有任何关系.
相反, 我们转向 Redis , 一个我们在 Instagram 上广泛使用的键值存储. Redis 是一把 key-value 的瑞士军刀; 而不是像 Memcached 那样普通的 "Set key,get key" 机制, 它提供了强大的聚合类型, 如有序集合和列表. 它具有可配置的持久化模型, 其中后台以指定的时间间隔保存, 并且可以设置主从同步. 我们所有的 Redis 都在主从服务器上运行, 从服务器设置为每分钟保存到磁盘.
首先, 我们决定以最简单的方式使用 Redis: 对于每个 ID,key 将是媒体 ID, 值将是用户 ID:
- SET media:1155315 939
- GET media:1155315
- > 939
然而, 在对此解决方案进行模型设计时, 我们发现 Redis 需要大约 70 MB 才存储 1,000,000 个 key. 根据我们需要的 300,000,000, 大约要 21GB 的数据, 已经比亚马逊 EC2 上的 17GB 实例类型更大.
我们向 Redis 的核心开发人员之一, 乐于助人的 Pieter Noordhuis 提出了意见, 他建议我们使用 Redis 哈希. Redis 中的哈希是字典, 可以非常有效地编码在内存中; Redis 设置'hash-zipmap-max-entries'配置散列可以有效编码的最大条目数. 我们发现这个设置最好在 1000 左右; 任何更高的配置 HSET 命令都会引起很明显的 CPU 使用. 有关更多详细信息, 你可以 查看 zipmap 源文件 .
为了用散列类型, 我们将所有媒体 ID 分配到 1000 个桶中(我们只取 ID, 除以 1000 并丢弃剩余部分). 这决定了属于哪个键, 接下来在该键的散列中, Media ID 是散列中的查找键, 用户 ID 是值. 一个例子, 给定媒体 ID 为 1155315, 它属于桶 1155(1155315/1000 = 1155):
- HSET "mediabucket:1155" "1155315" "939"
- HGET "mediabucket:1155" "1155315"
- > "939"
内存差异非常惊人; 使用我们的 1,000,000 个 key(编码为 1000 个哈希, 每个 1000 个子 key),Redis 只需要 16MB 存储. 扩展到 3 亿个 key, 总数不到 5GB, 事实上, 它甚至适合亚马逊上更便宜的 m1.large 实例类型, 大约是我们原本需要的更大实例成本的 1/3. 最重要的是, 散列中的查找仍然是 O(1), 非常快.
如果你对尝试这些感兴趣, 我们用于运行这些测试的脚本 可以作为 GitHub 上的 Gist (我们在脚本中有 Memcached 用于比较, 百万个 key 需要大约 52MB).
点击英文原文链接
更多文章欢迎访问: http://www.apexyun.com
公众号: 银河系 1 号
联系邮箱: public@space-explore.com
(未经同意, 请勿转载)
来源: http://www.tuicool.com/articles/YFZNnmb