redis为什么这么快?

一说到微服务缓存大家都想到使用redis来做,因为它快。支持10W+的qps。那它到底为什么这么快呢?今天来简单回顾一下。

 

内存操作

第一个肯定要说的是redis的内存操作,相对于关系型数据库的将数据存入磁盘。内存的操作速度就相当快。没有磁盘IO操作的耗时自然就快了。看过一个资料,CPU读取一次内存数据,大约需要100个时钟周期。这对于磁盘IO真的非常快了。

 

redisObject

redis的对象及数据结构设计也是它快的很重要的原因。
redis中并不是直接使用数据结构存储,而是通过redisObject对象操作数据。redisObject包含属性:type-数据类型,encoding-数据编码,ptr-底层数据结构等。

type

指redis提供的几种数据类型,例如:REDIS_STRING,REDIS_LIST这类的数据结构。

encoding

指当前存储的具体数据结构,例如:使用指令:set key 1时,value的encoding就是REDIS_ENCODING_INT(long型),再次set key hello时,value的encoding就会变成REDIS_ENCODING_RAW(简单动态字符串)或者REDIS_ENCODING_EMBSTR(embstr编码的简单动态字符串)。

RAW和EMBSTR简单的区别:REDIS_ENCODING_RAW简单动态字符串,创建redisObject 时分配一次内存,创建存放字符串的sdshdr时分配一次,共调用两次内存分配函数,适用于保存长字符串;REDIS_ENCODING_EMBSTR简单动态字符串,专门保存短字符串。创建redisObject和sdshdr共调用一次内存函数,所以可以获取一块连续的内存空间。更好的利用CPU缓存优势。

 

数据结构

数据结构也是一个redis设计的一个很重要的点,我就捡我了解的说一些。

SDS-simple dynamic string

简单动态字符串数据结构,底层是buf[]数组保存字符串,只不过他在数组种固定保存了几个值。

len

已使用字符串长度,等于buf长度,有人会问为什么保存len字段?因为这样获取长度时时间复杂度是O(1)。加快访问速度。

free

记录buf中未使用的字节数量,那为什么有free字段?为了防止缓冲区溢出,字符串扩展前先判断是否足够空间可分配,如果足够则直接扩展;如果不足则先重新进行内存分配,再扩展字符串。

redis内存重新分配的优化策略

1. 空间预分配,当SDS发生空间扩展时,程序不仅会给扩展出本次足够的内存空间,还会再预先分配出一块内存空间,并把大小存入free字段,这样,下次再扩展可以直接使用上次分配的未空间,而不必触发内存分配操作。

2. 惰性空间释放,前面提到的预分配是字符串扩展的情况。而当遇到缩容时,被施放的字符串空间不会立刻收回,而是放到free里,等待下次使用。这就是惰性释放,减少了内存释放的操作。

 

字符串变量的共享和适配

redis会创建一定范围内的整数对应的字符串对象用来共享使用。避免重复创建。使用redis.h/REDIS_SHARED_INTEGERS可以修改创建的共享字符串对象的数量,目前默认应该是0-9999,如果服务器要使用到这些对象时,就会直接使用共享字符串变量。

 

当前时间存储

redis会缓存秒级和毫秒级的系统unix时间戳,减少获取当前时间的系统调用。这个功能用于一些对时间精度要求不高的地方,例如日志。设置超时这类精度要求高的还是会获取系统时间的。

 

redis主从复制算法的优化

redis开始时主从复制是使用sync指令,每次复制master会生成一份RDB快照,然后传输给slave进行数据恢复。这样每次复制都是一个全量复制。性能消耗很大。后来2.8版本以后使用psync指令将复制分为完整重同步和部分重同步。只有从服务器第一次或者断开很长时间才使用完整重同步,而其他情况采用偏移量增量复制,将自身的偏移量告诉主服务,主服务会根据收到的offset和自身的offset将复制积压缓冲区中从服务丢失的写命令发送给从服务这就是部分重,同步避免全复制的性能消耗。

 

IO的多路复用

 

redis使用一个线程监听多个套接字,谁先有读写事件就处理谁,减少线程切换开销和IO阻塞,以提高CPU利用率。

 

单进程单线程?

其实redis并不是一个单进程单线程服务,例如它在bgsave时会fork出一个子线程去执行。它只不过是在接受请求网络模块使用的是单线程模式。其他的一些缓慢操作还是多线程去执行的。

而且最新的6.0+版本,redis已经支持了多线程模式,性能至少是单线程模式的一倍。如果单线程小数据包能达到10w+qps;那么多线程大概是20w+。

redis启动多线程原因:

1. 充分利用cpu资源。单线程只能利用到CPU的单一核心。

2. 利用多线程分担同步IO的读写负荷。

 

那么如何启用多线程?

io-threads-do-reads yes

io-threads 4(不要超过CPU核心数)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值