文章目录
- 1. C 语言字符串的“致命弱点”:`\0`
- 2. Redis 的解决方案:SDS (Simple Dynamic String)
- 3. 为什么这被称为“二进制安全”?
- 4. 深度对比
- 总结
要理解 Redis 的“二进制安全(Binary Safety)”,最直接的方法就是对比它与C 语言传统字符串处理方式的区别。
简单来说,二进制安全意味着:Redis 不会对你存入的二进制数据进行任何解释、限制或过滤。你存进去是什么,取出来就是什么。
1. C 语言字符串的“致命弱点”:\0
在 C 语言中,字符串是以\0(ASCII 码为 0 的空字符)作为结束标志的。
- 执行逻辑:当程序读取字符串时,它会从头开始扫,一旦遇到
\0,就认为这个字符串结束了。 - 后果:如果你想在字符串中间存入一张图片或一个压缩包的二进制数据,而这些数据中恰好包含
\0,C 语言函数就会“自作聪明”地提前截断,导致数据丢失。
2. Redis 的解决方案:SDS (Simple Dynamic String)
Redis 并没有直接使用 C 语言的字符串表示,而是自己封装了一个结构叫做SDS。它的核心改进在于:显式保存字符串的长度。
structsdshdr{intlen;// 已使用的字节长度intfree;// 未使用的字节长度charbuf[];// 实际保存数据的字节数组};- 不再数
\0:当 Redis 需要读取数据时,它不会去扫描\0,而是直接查看len属性。 - 长度决定一切:哪怕你的数据里有 100 个
\0,Redis 也会根据len的指示,老老实实地把这 100 个字节全部读出来。
3. 为什么这被称为“二进制安全”?
“安全”在这里的意思是:数据的原始二进制位(Bit)是受保护的。
因为 Redis 不依赖特殊的转义字符或结束符来处理数据,所以它可以存储任何形式的二进制数据,包括:
- 图片/视频/音频的字节流。
- Protobuf/JSON序列化后的对象。
- 加密后的密文(密文往往包含大量不可见字符和
\0)。
4. 深度对比
| 特性 | C 语言原生字符串 | Redis SDS (String) |
|---|---|---|
| 结束判断 | 扫描到\0停止 | 根据len长度直接读取 |
| 内容限制 | 不能包含\0,否则被截断 | 无限制,二进制安全 |
| 获取长度 | 需要遍历整个字符串O ( n ) O(n)O(n) | 直接读取len变量O ( 1 ) O(1)O(1) |
| 缓冲区溢出 | 容易发生(如果不检查长度) | 自动扩容,非常安全 |
总结
Redis 依然会在buf数组的末尾补一个\0,这仅仅是为了兼容某些 C 语言标准的库函数(比如打印日志)。但在处理你的业务数据时,它完全不以\0为准。
这种设计让 Redis 的 String 类型成为了一块**“万能内存胶布”**,可以贴任何类型的数据。
既然你提到了二进制安全,你是在研究 Redis 如何缓存复杂的 Java 对象序列化结果吗?