/** 问题1:为什么要用String类型?* 问题2:String它能存什么?* 问题3:String存储实现原理是什么?* 问题4:应用场景?** */1、为什么用String?原因:Redis是有C语音编写的,在C语音中本身是没有String的而是用Char[]。使用Char[]数组有违背redis的存储理念。说一下Char[]存储的不好之处:1):Char[]在存储之前必须要指定字符数组的大小,若果指定过大则导致内存浪费,过小则导致内存溢出。2):对Char[]字符数组的长度进行变更的时候需要重新分配内存。3):获取字符数组的长度的时候需要对字符数组进行遍历,时间复杂度为O(n)。4):结束符以\0为标准,像音频、视频等2进制的文件,它极有可能会出行数据不安全,会出现和预想的不一致的情况。基于上面的一些问题,Redis有自己的一套String的实现,它采用的就是SDS,若问SDS是什么,那它就是Redis中String字符串的实现。SDS存储字符串好处:1):不需要担心内存溢出的问题,若果有需要会自动扩容。2):String字符串长度变更不需要重新分配内存,可以通过"空间预分配"和"惰性空间释放"防止重新分配内存。3):获取字符串的长度的时候有自己的len属性来获取,() -> 时间复杂度为O(1)。4):String字符串读取的结尾有len的长度决定,避免出现数据丢失的问题。解释一下什么叫"空间预分配"和"惰性空间释放":空间预分配:Redis在对字符串进行修改的时候,若小于1MB则会分配额外的相同大小的内存空间+1个字节,其中一个字节用来保存空字符的。惰性空间释放:当字符串缩短的时候也不是立马进行内存重分配来回收多余的内存,而是通过free属性留着给将来使用。2、String能存储什么?Stirng字符串、int、float和一些JSON结构的字符串。说一下如果存/取JSON字符串的话,Redis首先是会进行序列化和反序列话的,这样难免会对序列化和反序列化进行额外的内存开销。3、存储实现原理:由于Redis是KV的形式进行存储的,所以他是通过hashtable来存储数据的,我们把它叫做外层的hash,redis中每个KV都是一个dictEntry(dict:字典;entry:实体),而每一个dictEntry里面有他的属性next指向下一个dictEntry。看下图:
可以看到dictEntry中的key是以SDS来存储的,也就是说key只能是字符串类型的。value是通过RedisObject来存储的,然后通过RedisObject来指向他的SDS,这里有个疑问既然是通过RedisObject类指向SDS,那为什么不直接用SDS呢来存呢?其实还是为了节约内存。另一个就是String的存储大小限制:int长整形的2^63-1的时候用int存储,小于44个字符(一个英文一个字符)用embstr存储,大于44用raw存储。embstr是只读的,一点进行修改就会变成raw类型存储。顺便说一下embstr和raw的区别:好处:embstr内存只需要分配一次(RedisObject和SDS是连续的),raw需要两次(redisObject和SDS);embstr在创建时少分配一次空间,删除时少释放一次空间,并且对象所有的数据是连续的方便寻找。坏处:embstr存储的数据很小并且不能修改,一旦修改就会变成raw类型,这是因为embstr字符串长度增加是要重新分配内存的,RedisObject和SDS都会重新分配空间,因此是只读的。4、应用场景:缓存、计数器incr命令、限流(incr设置界限达到界限限制访问)、分布式数据共享(redis session)、全局id(incr命令,因为是自增的)、分布式锁(setnx锁+expire过期时间)