redis优化编码之字符串

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: Redis数据结构之字符串

redis 优化编码之字符串

 字符串优化

字符串对象是redis内部最常用的数据类型。

  • 所有的键是字符串对象
  • 值对象除了整数之外都是使用字符串存储
lpush cache:type "redis" "tair" "memcache" "leveldb"

创建如上一个链表 需要创建一个链表对象和四个字符串对象。至少需要五个字符串对象。

字符串结构

redis为采用原生C语言类型的字符串结构,拥有自己的字符串结构 ----内部简单动态字符串(simple dynamic string , SDS)
image

graph LR
    subgraph SDS字符串结构体
        c[char buf ] -->cexp[字节数组]
     end
   subgraph SDS字符串结构体
        b[int free ] --> bexp[未用字节长度]
    end
   subgraph SDS字符串结构体
        a[int len ] --> aexp[已用字节长度] 
    end
    style aexp fill:#f9f,stroke:#333,stroke-width:2px
    style bexp fill:#f9f,stroke:#333,stroke-width:2px
    style cexp fill:#f9f,stroke:#333,stroke-width:2px

特点如下:

  • [ ] O(1) 时间复杂度获取:字符串长度、已用长度、未用长度
  • [ ] 内部实现空间预分配机制 降低再分配
  • [ ] 惰性删除机制,字符串缩减后的空间不释放,作为预分配空间保留

预分配机制

字符串存在预分配机制,需要注意预分配带来的内存浪费。

阶段一

image

graph LR
    subgraph SDS字符串结构体
        c[char buf ] 
     end
   subgraph SDS字符串结构体
        b[free = 0 ] 
    end
   subgraph SDS字符串结构体
        a[len = 60 ] 
    end
      c  -->cexp[used+free+\O=61字节]

    style cexp fill:#f9f,stroke:#333,stroke-width:2px

    这里忽略int类型和free字段消耗的8字节

阶段二

image

graph LR

    subgraph SDS字符串结构体
        c[char buf ] 
     end
   subgraph SDS字符串结构体
        b[free = 120 ] 
    end
   subgraph SDS字符串结构体
        a[len = 120 ] 
    end
      c  -->cexp[used+free+\O=241字节]

    style cexp fill:#f9f,stroke:#333,stroke-width:2px

追加操作后字符串对象预分配一倍容量作为预留空间-大量追加操作内存重分配造成内存碎片

阶段三

image

graph LR

    subgraph SDS字符串结构体
        c[char buf ] 
     end
   subgraph SDS字符串结构体
        b[free = 0 ] 
    end
   subgraph SDS字符串结构体
        a[len = 120 ] 
    end
      c  -->cexp[used+free+\O=121字节]

    style cexp fill:#f9f,stroke:#333,stroke-width:2px

降低一倍的空间同时碎片率也降低了

测试用例环境:

  • redis 3.2.8
  • mem_allocator libc
  • maxmemory 5G
  • model standalone

数据量阶段操作说明命令内存内存碎片率
200W阶段1新插入200W数据set367.33M1.79
阶段2在阶段1的基础上追加1倍数据append760.21M1.62
阶段3重新插入200W数据 value是之前的1倍set500.84M1.72


数据量阶段操作说明命令内存内存碎片率
400W阶段1新插入400W数据set690.91M1.8
阶段2在阶段1的基础上追加1倍数据append1.45G1.63
阶段3重新插入400W数据 value是之前的1倍set961.76M2.48

数据量阶段操作说明命令内存内存碎片率
600W阶段1新插入600W数据set1.00G1.8
阶段2在阶段1的基础上追加1倍数据append2.16G1.63
阶段3重新插入600W数据 value是之前的1倍set1.40G2.48

数据量阶段操作说明命令内存内存碎片率
800W阶段1新插入800W数据set1.3G1.31
阶段2在阶段1的基础上追加1倍数据append2.85G1.65
阶段3重新插入800W数据 value是之前的1倍set1.831.19

数据量阶段操作说明命令内存内存碎片率
1000W阶段1新插入1000W数据set1.66G1.8
阶段2在阶段1的基础上追加1倍数据append3.60G1.63
阶段3重新插入1000W数据 value是之前的1倍set2.84G1.46

上述进行了200W、400W、600W、800W、1000W 数据量的 测试,内存以及内存碎片率

  • 同样的数据追加后内存的消耗非常严重。

  • 字符串预分配的方式 是为防止修改数据操作不断重分配内存和字节数据

  • 造成内存浪费,并不是每次都是翻倍

    • 第一次创建len 等于数据实际大小 free等于0, 不做预分配
    • 修改后 free空间不足,且数据小于1M,则分配1倍(len=60bytes,free=0,再追加60bytes 预分配120bytes 。总空间就是60+60+120+ 1 bytes)
    • 修改后free空间不足,且数据大约1M 则每次预分配1M (len=30MB ,free=0,追加100bytes 预分配1MB 总空间 30MB+100bytes+1MB + 1bytes)

总结

  • 尽量减少字符串频繁修改操作 如append,setrange

  • 改为直接使用set修改字符串

  • 降低预分配带来的内存浪费和碎片
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
4月前
|
存储 缓存 NoSQL
redis数据结构-字符串
redis数据结构-字符串
42 1
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万级数据统计优化实践
【10月更文挑战第21天】 在处理大规模数据集时,传统的单体数据库解决方案往往力不从心。MySQL和Redis的组合提供了一种高效的解决方案,通过将数据库操作与高速缓存相结合,可以显著提升数据处理的性能。本文将分享一次实际的优化案例,探讨如何利用MySQL和Redis共同实现百万级数据统计的优化。
100 9
|
1月前
|
SQL 关系型数据库 MySQL
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:优化百万数据查询的实战经验
【10月更文挑战第13天】 在处理大规模数据集时,传统的关系型数据库如MySQL可能会遇到性能瓶颈。为了提升数据处理的效率,我们可以结合使用MySQL和Redis,利用两者的优势来优化数据查询。本文将分享一次实战经验,探讨如何通过MySQL与Redis的协同工作来优化百万级数据统计。
81 5
|
2月前
|
NoSQL Redis
Redis 字符串(String)
10月更文挑战第16天
48 4
|
2月前
|
NoSQL 关系型数据库 MySQL
MySQL与Redis协同作战:百万数据量的优化实录
【10月更文挑战第6天】 在现代互联网应用中,随着用户量的增加和业务逻辑的复杂化,数据量级迅速增长,这对后端数据库系统提出了严峻的挑战。尤其是当数据量达到百万级别时,传统的数据库解决方案往往会遇到性能瓶颈。本文将分享一次使用MySQL与Redis协同优化大规模数据统计的实战经验。
163 3
|
2月前
|
NoSQL 关系型数据库 BI
记录一次MySQL+Redis实现优化百万数据统计的方式
【10月更文挑战第13天】 在处理百万级数据的统计时,传统的单体数据库往往力不从心,这时结合使用MySQL和Redis可以显著提升性能。以下是一次实际优化案例的详细记录。
150 1
|
2月前
|
消息中间件 分布式计算 NoSQL
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
大数据-41 Redis 类型集合(2) bitmap位操作 geohash空间计算 stream持久化消息队列 Z阶曲线 Base32编码
29 2
|
3月前
|
存储 缓存 NoSQL
3)深度解密 Redis 的字符串
3)深度解密 Redis 的字符串
37 1
|
4月前
|
C# 开发者 UED
WPF开发者必备秘籍:深度解析文件对话框使用技巧,打开与保存文件原来如此简单!
【8月更文挑战第31天】在WPF应用开发中,文件操作是常见需求。本文详细介绍了如何利用`Microsoft.Win32`命名空间下的`OpenFileDialog`和`SaveFileDialog`类来正确实现文件打开与保存功能。通过示例代码展示了如何设置文件过滤器、初始目录等属性,并使用对话框进行文件读写操作。正确使用文件对话框能显著提升用户体验,使应用更友好易用。
102 0

相关产品

  • 云数据库 Tair(兼容 Redis)