Redis降低内存占用(一)

引子

深圳,雨,单休周末。午觉醒来,重新打开许久没看的《redis实战》,今天下午就看看 redis 性能优化部分。

降低Redis的内存占用所带来的好处:

  • 减少创建、加载快照的耗时
  • 提升载入、重写AOF文件的效率
  • 缩短从服务器的同步耗时
  • 提高Redis的内存使用效率

书中所提到的主要优化策略有:

  • 短结构
  • 分片结构
  • 打包存储二进制位和字节

下面一一道来。

一、 短结构

在列表、散列和有序集合的长度较短或者体积较小的时候,Redis 可以选择使用一种名为压缩列表的(ziplist)的紧凑存储方式来存储这些结构。

压缩列表是列表、散列和有序集合这三种不同类型的对象的一种非结构化表示:

普通情况下,Redis中数据结构的底层实现方式(这一部分知识在《redis实战》一书中提及的很少,在《redis设计与实现》一书中有比较详细的阐述):

  • 列表——双链表
  • 散列——散列表
  • 有序集合——散列表+跳跃表

启用压缩列表的情况下:

  • 序列化的方式保存数据
  • 每次读取需要解码
  • 每次保存需要重新编码
  • 可能对内存中的数据进行移动

1. 压缩列表的实现

不使用压缩列表的额情况下,以列表数据结构为例:

  • 用来实现列表的双向链表,由于需要保存前后节点的指针信息,以及当前数据指针,加上保存自己的数据长度、剩余空间的两个整数。
  • 举个例子:在32位系统上。一个列表中的一个长度为3个字节元素,需要至少21字节的额外空间

而启用压缩列表的情况下:

  • 压缩列表是由节点组成的序列。每个节点需要两个额外的描述数据:一个用来记录上一个节点长度,一个用来记录当前节点的长度
  • 举个例子:在32位系统上。一个列表中的一个长度为3个字节元素,只需要2字节的额外空间

显而易见的,Redis中当保存的每个数据长度都很短时,如果不做处理,那么Redis用来描述这个数据位置的数据可能远远大于数据的本身,这就是为什么需要使用压缩列表。

启用压缩列表

1
2
3
4
5
6
list-max-ziplist-entries 512    # 列表结构使用压缩列表表示的限制条件。
list-max-ziplist-value 64 #
hash-max-ziplist-entries 512 # 散列结构使用压缩列表表示的限制条件
hash-max-ziplist-value 64 #(Redis 2.6 以前的版本会为散列结构使用不同的编码表示,并且选项的名字也与此不同)。
zset-max-ziplist-entries 128 # 有序集合使用压缩列表表示的限制条件。
zset-max-ziplist-value 64 #

列表、散列、有序集合可以使用压缩列表实现,而集合则不太相同。

2. 集合的整数集合编码

集合当满足以下条件时可以进行优化:

  • 所有成员都可以被解释成十进制整数
  • 处于平台的有符号整数范围之内
  • 集合成员足够少

满足上述条件的集合,Redis将会以整数集合这种底层数据结构来实现当前集合。

1
set-max-intset-entries 512      # 集合使用整数集合表示的限制条件。

超过以上设置的集合会被换为用散列表来实现。

3. 不成熟的优化所带来的的问题

在开始的时候我们提到过压缩列表需要额外的编码、解码过程。

可以看到加入我们错误的设置了一个阈值,比如将一些很长的数据用压缩列表来保存,而且同时这一部分的数据属于热点数据,读写次数高。

那么每次编码解码所带来的性能损失,将大于空间占用的降低。

参考资料

《Redis实战》源码:https://github.com/huangz1990/riacn-code/blob/master/ch09_listing_source.py


后续将介绍分片、打包,待续。。。