在 Redis 中,存一个 中
字,可能占 3 个字节,也可能占两个字节。存一个 10
占用 2 个字节,存 100
要占 3 个字节。这是因为 Redis 用了二进制安全的技术,不将数据进行任何转换,以二进制的方式来什么存什么。为此,同一个 Redis 服务的客户端要统一编码格式,不然数据的读和存会有不一致的问题。
非二进制安全
首先,正如其名“二进制安全”的作用就是保证了数据的安全,那他的反例是什么呢?
比如在 C 语言中的 strlen()
函数就是非二进制安全的,当你用语句 strlen("Hello,\0 World!");
时,它的结果是 5,因为它将 \0
视作字符串的结束符,即 C 语言默认认为某些字符有特殊含义,会将它做特殊的处理。(run C online)
相比之下 PHP 的 strlen()
函数就是二进制安全的,strlen("Hello,\0 World!");
会正确地返回 13。(run PHP online)
二进制安全
“二进制安全”就是说你传给我的数据的二进制是什么样,存在我这里的就是什么样,只要传给到我,我肯定保证它在这里是不会被篡改的。(我不会对这些数据进行再编码,再序列化)。
Redis 用二进制安全的好处:存和取都按字节数组来,在这里没有类型,不会变化存储的数据,不会有溢出和覆盖,不会有乱码问题。
Redis 二进制安全的一些现象
那关系到二进制安全,我们不注意时,会出现一些“看起来”摸不着头脑的问题。
比如,当 Terminal 设置的编码格式不同时,其 redis-cli set 的中文字符串在 redis 中存的数据不同。
比如都用 set k1 中
命令,Terminal 设置的编码格式为 UTF-8 时,“中”是“\xe4\xb8\xad”,用 get
命令取到的也是此字符串,而用 GBK 存储时为“\xd6\xd0”。用 strlen
命令返回的结果也不同,前者为 3 后者为 2。
这是因为命令行工具会用不同的编码格式将中文编码成不同的二进制数据,然后传给 Redis 存储起来。
redis 返回的数据默认是用字符串形式返回的。当启动 redis-cli 时加上参数 --raw
时,则能获取到 redis 存储的原始二进制数据,此时 Terminal 便也会对这些二进制数据进行解码。如果 Terminal 取到了不同于自己的编码格式的 Terminal set 的数据就会产生乱码问题。
因此,在项目工程中,如果有两个服务分别开启一个客户端去连一个 Redis 时,一定要注意编码格式统一的问题。
网友评论