节约内存:Instagram的Redis实践

Instagram能够说是网拍App的始祖级应用,也是当前最火热的拍照App之一,Instagram的照片数量已经达到3亿,而在Instagram里,咱们须要知道每一张照片的做者是谁,下面就是Instagram团队如何使用Redis来解决这个问题并进行内存优化的。 html

首先,这个经过图片ID反查用户UID的应用有如下几点需求: redis

  • 查询速度要足够快
  • 数据要能所有放到内存里,最好是一台EC2的 high-memory 机型就能存储(17GB或者34GB的,68GB的太浪费了)
  • 要合适Instagram现有的架构(Instagram对Redis有必定的使用经验,好比这个应用
  • 支持持久化,这样在服务器重启后不须要再预热

Instagram的开发者首先否认了数据库存储的方案,他们保持了KISS原则(Keep It Simple and Stupid),由于这个应用根本用不到数据库的update功能,事务功能和关联查询等等牛X功能,因此没必要为这些用不到的功能去选择维护一个数据库。 sql

因而他们选择了Redis,Redis是一个支持持久化的内存数据库,全部的数据都被存储在内存中(忘掉VM吧),而最简单的实现就是使用Redis的String结构来作一个key-value存储就好了。像这样: 数据库

SET media:1155315 939
GET media:1155315
> 939

其中1155315是图片ID,939是用户ID,咱们将每一张图片ID为做key,用户uid做为value来存成key-value对。而后他们进行了测试,将数据按上面的方法存储,1,000,000数据会用掉70MB内存,300,000,000张照片就会用掉21GB的内存。对比预算的17GB仍是超支了。 服务器

NoSQLFan:其实这里咱们能够看到一个优化点,咱们能够将key值前面相同的media去掉,只存数字,这样key的长度就减小了,减小key值对内存的开销【注:Redis的key值不会作字符串到数字的转换,因此这里节省的,仅仅是media:这6个字节的开销】。通过实验,内存占用会降到50MB,总的内存占用是15GB,是知足需求的,可是Instagram后面的改进任然有必要架构

因而Instagram的开发者向Redis的开发者之一Pieter Noordhuis询问优化方案,获得的回复是使用Hash结构。具体的作法就是将数据分段,每一段使用一个Hash结构存储,因为Hash结构会在单个Hash元素在不足必定数量时进行压缩存储,因此能够大量节约内存。这一点在上面的String结构里是不存在的。而这个必定数量是由配置文件中的hash-zipmap-max-entries参数来控制的。通过开发者们的实验,将hash-zipmap-max-entries设置为1000时,性能比较好,超过1000后HSET命令就会致使CPU消耗变得很是大。 nosql

因而他们改变了方案,将数据存成以下结构: post

HSET "mediabucket:1155" "1155315" "939"
HGET "mediabucket:1155" "1155315"
> "939"

经过取7位的图片ID的前四位为Hash结构的key值,保证了每一个Hash内部只包含3位的key,也就是1000个。 性能

再作一次实验,结果是每1,000,000个key只消耗了16MB的内存。总内存使用也降到了5GB,知足了应用需求。 测试

NoSQLFan:一样的,这里咱们仍是能够再进行优化,首先是将Hash结构的key值变成纯数字,这样key长度减小了12个字节,其次是将Hash结构中的subkey值变成三位数,这又减小了4个字节的开销,以下所示。通过实验,内存占用量会降到10MB,总内存占用为3GB

HSET "1155" "315" "939"
HGET "1155" "315"
> "939"

优化无止境,只要肯琢磨。但愿你在使用存储产品时也能如此爱惜内存。

来源:instagram-engineering.tumblr.com

相关文章
相关标签/搜索