找工作面试的时候无意中发现了Redis相关的问题。面试前按照平时的套路准备,Redis的5种常用数据结构,Redis的持久化策略,Redis分布式锁的实现,简单的发布订阅等等,想着终于应接不暇了byRedis问的第一个问题~~面试官:看你简历上对常见的数据结构很熟悉,说说吧:常用的类型有5种,string,list,set,zset,hash(很自豪)面试官:然后说说你用过哪些数据结构_I:String用的最多,里面一般存放json字符串_面试官:那你知道Redis内部是如何实现它的string的吗?_我自己:呃~,我知道Redis是用C语言写的,但是具体实现不知道~我来了~~~有没有相同经历的朋友?回去之后补了一些关于Redis原理的知识点。正好最近在总结面试经验,所以才有了今天的这篇文章。本文将讲到以下内容:RedisString的实现RedisString的性能优势RedisString的实现Redis虽然是用C语言编写的,但它并没有直接使用C语言的字符串,而是实现了一组字符串。目的是提高速度和性能。可见Redis在高性能方面也下了一番功夫。Redis构建一个简单的动态字符串(SimpleDynamicString),简称SDS1.SDS代码结构structsdshdr{//Recordtheusedlengthintlen;//Recordthelengthoftheidleunusedintfree;//字符数组char[]buf;};安全数据表?我勒个去?可能对这个名字不熟悉的朋友可能会对这个名字产生疑问。只是一个名词而已,不要着急,我们还是要着重于欣赏和借鉴Redis的设计思想。下面画一张图来说明一下。Redis的字符串也会遵守C语言字符串的实现规则,即最后一个字符为空字符。但是,这个空字符不会被计入len。关注微信公众号:Java技术栈,后台回复:redis,可以领取我整理的N篇Redis教程,都是干货。2.SDS动态扩展特性SDS最强大最精彩的特性在于它的Dynamic。动态改变长度。比如上图,一开始s1只有5个空闲席位,后面还需要加上'world'的6个字符,显然是不够的。现在是什么?Redis会做以下三个操作:计算大小是否足够开辟空间满足需要的大小开辟一个空闲的空闲空间,长度与使用的大小len相同(如果len<1M)开辟一个空闲的空闲空间长度为1M(iflen>=1M)到目前为止,有没有小伙伴觉得这个实现有点类似于Java的List实现?看完之后会更像。推荐阅读:为什么Redis这么快?Redis字符串的性能优势快速获取字符串长度,避免缓冲区溢出减少空间分配次数,提高内存使用效率1.快速获取字符串长度,再看上面的SDS结构:structsdshdr{//记录使用的长度intlen;//记录空闲和未使用的长度intfree;//字符数组char[]buf;};由于使用的字符长度len存储在SDS中,所以当想获取字符串长度时,直接返回len即可,时间复杂度为O(1)。如果在C语言中使用一个字符串,它的字符串长度获取函数时间复杂度是O(n),n是字符个数,因为它是从头到尾遍历并相加(到空字符'\0')。2.避免缓冲区溢出strcat向C语言字符串追加字符串时,需要提前开辟所需的空间。如果不开辟空间,可能会造成缓冲区溢出,影响程序中的其他代码。如下图所示,有一个字符串s1="hello"和字符串s2="baby"。现在需要执行strcat(s1,"world"),执行前没有s1的空间,所以会出现缓冲区溢出。对于Redis来说,由于每次追加一个字符串都会检查是否有足够的空间,所以不存在缓冲区溢出问题。每次append操作前都会做如下操作:计算大小是否足够开辟空间满足需要的大小3.减少空间分配次数,提高内存使用效率字符串append操作会涉及到内存分配问题,但是内存分配问题会涉及到内存分区算法和系统调用,频繁出现会影响性能,所以这对于性能至上的Redis来说是绝对不能承受的。推荐:Redis内存满了怎么办?因此,采取了以下两种优化措施:惰性空间回收的空间和分配1.空间预分配对于追加操作,Redis不仅会开辟足够的空间,还会预分配未使用的空间(free),供下次操作使用.至于未使用空间(free)的大小,由修改后的字符串长度决定。当修改字符串长度len<1M时,分配一个与len长度相同的未使用空间(free)当修改字符串len>=1M时,分配一个1M长度未使用空间(free)采用这种预分配策略,会减少内存分配的次数,因为在分配之前,会检查现有空闲空间是否足够,如果足够,则不会打开~2.Lazyspacerecovery相反以上情况,lazyspacerecovery适用于字符String缩减操作。比如有一个字符串s1="helloworld",对s1进行sdstrim(s1,"world")操作。操作完成后,Redis不会立即回收减少的部分,而是分配给下一个需要内存的程序。.当然,Redis也提供了回收内存的api,可以手动来回调用,收缩一部分内存。至此结束~下次遇到这个问题可以再聊聊,哈哈哈~
