Redis如何做内存优化「redis增加内存」
场景:
一些大型电商系统大量使用redis,我们将大量的商品基础数据和促销方案数据存放在redis集群中,单台服务器内存百G,体量也是相当庞大。所以我们也在不断的想方法优化减少redis的内存使用量,把我们的优化方法和碰到的实际问题与大家分享。
采用Hash代替<K,V>键值对存储
因为是存放商品维度的数据,商品skuId往往会作为key,而一个商品sku会存在多个信息,比如商品名称,商品图片地址,商品促销语等等,比较容易想到的存储结构是采用Hash,将一个商品的多个信息作为hash里的不同field来存放。
什么是ziplist?
Redis官方对于ziplist的定义是(出自ziplist.c的文件头部注释):
The ziplist is a specially encoded dually linked list that is designed to be very memory efficient. It stores both strings and integer values, where integers are encoded as actual integers instead of a series of characters. It allows push and pop operations on either side of the list in O(1) time.
翻译一下就是说:ziplist是一个经过特殊编码的双向链表,它的设计目标就是为了提高存储效率。ziplist可以用于存储字符串或整数,其中整数是按真正的二进制表示进行编码的,而不是编码成字符串序列。它能以O(1)的时间复杂度在表的两端提供 push 和 pop 操作。
实际上,ziplist充分体现了Redis对于存储效率的追求。一个普通的双向链表,链表中每一项都占用独立的一块内存,各项之间用地址指针(或引用)连接起来。这种方式会带来大量的内存碎片,而且地址指针也会占用额外的内存。而ziplist却是将表中每一项存放在前后连续的地址空间内,一个ziplist整体占用一大块内存。它是一个表(list),但其实不是一个链表(linked list)。
另外,ziplist为了在细节上节省内存,对于值的存储采用了变长的编码方式,大概意思是说,对于大的整数,就多用一些字节来存储,而对于小的整数,就少用一些字节来存储。我们接下来很快就会讨论到这些实现细节。
优化思路
善用Hash,List,ZSet的ziplist压缩特性
Redis针对Hash,List,ZSet都实现了ziplist的压缩存储,可以通过配置最大元素不超过512,每个元素大小不超过64bytes,来判断是否要采用 !ziplist压缩格式 存储。
注意:虽然这个ziplist是否启用做成了配置参数,但对这个配置参数的修改要谨慎,因为ziplist是一个连续的数组空间,查找效率不是O(1)的,如果设置元素超过512太多,可能导致查找效率降低,反而影响性能。那为什么Redis会采用512*64bytes这样的默认配置呢?据说是这个大小可以被加载进CPU的Cache里,所以即使不是O(1),查找效率也是很快的。
优先使用数字类型,比String类型省空间
在Redis的内部,不管是数字类型,String类型,都会统一用一个叫redisObject的对象做一层封装:
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
可见,一个简简单单的”hello world”在redis里都不是直接11个bytes就搞定的,还有很多附加的属性,比如引用计数(内存回收)refcount,lru清理等信息。
但如果使用了上面提到的ziplist,redis对ziplist里元素做了裁剪,让数据更紧凑,所以针对数字,做了一些特别处理:
* |11000000| - 1 byte
* Integer encoded as int16_t (2 bytes).
* |11010000| - 1 byte
* Integer encoded as int32_t (4 bytes).
* |11100000| - 1 byte
* Integer encoded as int64_t (8 bytes).
* |11110000| - 1 byte
* Integer encoded as 24 bit signed (3 bytes).
* |11111110| - 1 byte
* Integer encoded as 8 bit signed (1 byte).
* |1111xxxx| - (with xxxx between 0000 and 1101) immediate 4 bit integer.
* Unsigned integer from 0 to 12. The encoded value is actually from
* 1 to 13 because 0000 and 1111 can not be used, so 1 should be
* subtracted from the encoded 4 bit value to obtain the right value.
先用1byte来表示不同的encode,针对大小不同的数字,分别采用不一样的内存空间来存储,比如0-127就是2个字节,128-32768就是4个字节等等。所以算下来,和String相比,大部分情况下更省内存。
相关文章
- 五大专业值得期待的专业「以后五年后的热门专业是什么」
- 为什么传统线下经销商很少能做好电商工作「线上销售能取代线下销售吗」
- 电商运营的发展前景怎么样「电商运营工作怎么样」
- 浅谈第三方支付「中金支付是什么东西」
- 跨境电商支付宝「洛菲纳跨境电商正规吗」
- 数字人民币和支付宝,微信支付的区别「数字货币与支付宝有什么区别」
- 数字证书干嘛用的「你真辣什么意思」
- 新手如何选项目赚到人生的第一桶金「普通人如何赚取人生第一桶金」
- 游戏支付接口要怎么对接第三方支付平台「第三方支付对接教程」
- 「承泽观察•平台经济40评之三十五」黄卓:中国金融科技平台为何发展如此快速
- 宁波视频剪辑培训班「pr视频剪辑培训班」
- 快驴生鲜配送公司「重庆美团快驴」
- 广州渔村海鲜「海南农场自建房」
- 为什么要做抖音电商「做得好的短视频电商」
- 微商母婴坑人「母婴实体店是不是会消失」
- 618直播带货排行榜「国内直播带货主播排名」
- 陌陌人气主播成都牛牛「陌陌主播舞蹈胡萝卜」
- 快手上的瑜大公子收入「直播带货网红第一名是谁」