Redis的优势
Redis 存储使用的是内存,这是它快的主要原因。
内存读写速度快,能做到高吞吐、低延迟。内存相比于硬盘,不用经过过多的系统调用就可以读写数据。且代码实现上更简单,在硬盘上的资源我们还需要打开一个数据流去进行读写, 完事后再关闭到这个数据流;内存内的数据能直接被读写。
所以在使用内存的时候,只需要考虑给 Redis 分配多大的内存就行。
但这也引申出来一个新的问题,这个内存得分配多大?这是一个经验性的问题,也是一个相对来说比较模糊的问题。
Redis 内部使用的是单线程。
单线程是顺序处理事务,但多线程是多路一起处理事务,这是一个并行的操作。
从上文来看明显的看出多线程会更好,但多线程更好的前提就是处理好线程的上下文切换、事务锁以及复杂度等问题。
我们都知道多路复用里为了解决线程上下文切换会带了很大的开销做了多少次优化,这显然是一个比较严重的问题。
另外,多线程需要为了保证资源的原子性,使用事务锁去达到资源互斥。假设没有事务锁,两个事务处理的时候共同对一个资源(包括数据)进行操作,那么这个资源(包括数据)便会出现操作歧义,究竟哪个操作先哪个操作后不知道,就会出问题。加锁去实现资源互斥又是需要消耗额外的性能。
上面这两个问题想要解决就已经会大大提高开发和维护的复杂度了,别提还有其他的问题需要解决。
综上,整体如果使用多线程去实现 Redis 会发现复杂度很大,还不如使用单线程。
同时,Redis 作为在内存上的非关系型数据库,CPU处理事务的速度比在硬盘上的数据库要快很多,这意味着CPU瓶颈实际上很难出现,反而是内存和网络IO的瓶颈会很容易出现。
想象一下内存小,那处理事务的速度可能会比待处理事务出现的要快,一次就处理一点事务,相当于大水管流小水流,浪费了高速性。
而且网络IO传输东西过来的速度慢也会影响处理,这关系到网络的带宽以及传输过程中IO的效率。想象一下有一个水槽,大水管流出,但小水管流入,那水槽内的水一下就空了。
Redis 采用了IO多路复用。
Redis 采用IO多路复用这一模型,我们了解过IO多路复用的出现历程以及它本身的优势就知道,相比于阻塞IO模型、非阻塞IO模型等,IO多路复用相比于它们,都有着一些更好的优化(例如一直阻塞占用资源做无效操作也解决了,频繁的轮询也解决了,上下文切换的开销被优化了)。
具体去看我的《IO多路复用》这一篇文章,能增加一定的理解。
Redis 底层有设计好的数据结构。
Redis 底层用C语言实现了一些较为高阶的数据结构,很好的提高了性能。
Redis 数据类型对应底层的数据结构:
- String → 简单动态字符串
- List → 双向链表(核心)、压缩列表
- Hash → 哈希表(核心)、压缩列表
- Sorted Set → 跳表(核心)、压缩列表
- Set → 整数数组(核心)、压缩列表
额外:
跳表,又叫做跳跃表、跳跃列表,在有序链表的基础上增加了“跳跃”的功能。
跳表相比于一般链表来说要快得多。一般链表不用算法要找一个数就只能从头到尾去遍历;而跳表是根据当前节点的索引去跳转到下一个节点,一直对比跳转直至找到对应的数或者没找到跳转到表末。
跳表增加了索引,占据了更多的内存空间,但相对的空间换取时间,使得跳表比一般链表要快很多,减少了搜索次数。
另外,出现 Redis 内存利用紧张的问题与它自身底层跳表占用更多内存空间并不冲突。正因为跳表占据了更多的内存空间,才导致了 Redis 的内存利用紧张的问题。
补充一点:
Redis 是一个计算向数据移动的数据库,计算向数据移动的意思就是我们开发如果想要拿去 Redis 内的数据时,只需要通过Key
去直接获取对应的数据就行。
而数据向计算移动先要做的操作就是将所有数据都移动到开发中,再经过反序列手段解码出来再找自己想要用的。
想象一下,计算向数据移动像一个在家附近的书库,里面所有的书都分好了类打好了标签,我们想要某本书时,就只需要我们知道那本书的类型和对应的标签就能很快的找到了。
而数据向计算移动,就像一个书本仓库在自己家里头,里面堆满了各色各样的未拆包装的书,我们还得先把包装拆了才知道里面有什么书,然后再根据书打的标签在这一堆书里找到想要的书。
上面的书就是数据
value
,标签和分类就是大小KEY
。综上可以看出,这也是为什么计算向数据移动的数据库逐渐把数据向计算移动的数据库替代了,因为当数据量庞大的时候,处理业务时数据向计算移动的数据库使用过于消耗资源与操作不便。
评论(0)