简介redis混合存储实例是阿里云自主研发的完全兼容Redis协议和特性的混合存储产品 。通过将部分冷数据存储到磁盘,在保证绝大部分访问性能不下降的基础上,大大降低了用户成本并突破了内存对Redis单实例数据量的限制 。
与Redis高性能内存型实例差别Redis高性能内存型实例中,所有的Key和Value都存储在内存中以达到极致性能 。
Redis混合存储型实例中,所有的Key和经常访问的Value会被保存在内存中,保证绝大部分请求的极致性能 。不常访问的Value(冷数据)则会被存储到磁盘上,以达到内存利用最高性价比 。
产品优势
- 简单易用
- 完全兼容Redis协议,用户无需修改任何代码 。
- 低成本
- 相同数据量下,NVMe盘成本仅为内存的1/10 。
- 大容量
- 突破内存容量限制,单实例最高可支持TB级别的数据容量 。
- 高性能
- Redis混合存储型实例的绝大部分热点请求直接从内存获取,其性能与高性能内存型实例完全一致 。后台异步IO,冷数据访问不影响正常请求的响应 。在90%数据落在磁盘上的极端场景下,正态访问的QPS仍可达纯内存性的70% 。底层存储采用阿里自研下一代高性能全用户态存储引擎Alibaba FusionEngine:通过结合上层应用深入定制,以及与底层硬件深度结合,将新一代存储介质如NVMe SSD性能发挥到极致 。4KB数据读取速度在20us左右,相比业界同类引擎性能有80%提升 。
文章插图
存储模型
文章插图
在Redis混合存储实例中,我们将所有的Key和经常访问的Value保留在内存中,将不经常访问的Value保存在磁盘上 。之所以在内存中保留所有Key是处于以下两点考虑:
- Key的访问频度比Value要高很多 。
- 作为KV数据库,通常的访问请求都需要先查找Key确认Key是否存在,而要确认一个key不存在,就需要以某种形式检查所有Key的集合 。在内存中保留所有Key,可以保证key的查找速度与纯内存版完全一致 。
- Key的大小占比很低 。
- 在通常的业务模型里面,即使是普通字符串类型,Value比Key要大几倍 。而对于Set,List,Hash等集合对象,所有成员加起来组成的Value更是比Key大了好几个数量级 。
因此,Redis混合存储实例最适合以下使用场景:
- 数据访问不均匀,存在热点数据;
- 内存不足以放下所有数据,且Value较大(相对于Key而言)
文章插图
Redis混合存储实例采用单工作线程的模式,主线程为工作线程,负责处理用户请求等主要逻辑 。此外,Redis混合存储实例中根据需要会配置若干个独立的IO线程负责与磁盘进行交互读写数据,IO线程读写数据时,主线程仍可继续响应其它用户请求 。
数据从内存到磁盘
- 在周期巡检函数serverCron中,如果发现当前内存快满了,大于设定的阈值vm-max-memory(略小于maxmemory)时,会尝试挑选出一些key,将其Value保存到磁盘;
- 挑选的维度为最近访问时间和value大小, 公式为swAppability = age*log(估算内存大小) 。
- 主线程为挑选出的value生成IO任务,加入到IO任务队列中;
- IO线程会从IO任务队列中取出任务,将Value存储到底层存储引擎(RocksDB)中, 并通知主线程 。
- 主线程收到通知后释放Value所占用内存并标记内存中该Key对应的Value已被存储到磁盘上 。
- 当Redis混合存储实例收到用户请求时,会先判断请求是否需要读取对应Key的Value;
- 如果请求不需要读取相关value(比如set foo bar是不需要关心foo这个key原有的值是多少的)或者value已经在内存中,则正常执行该命令;
- 如果有涉及到的Value不在内存中,主线程会对应生成一个读取Value的IO任务,加入到IO任务队列中;
- 主线程将需要等待IO任务完成的客户端加入到等待列表,然后继续处理其余客户端的请求;
- IO线程获取到读取Value的IO任务时,从底层存储引擎中读取数据,并通知主线程;
推荐阅读
- redis解析:缓存及常见问题
- 如何用Redis实现购物车的增删改和清空
- Redis数据淘汰算法
- 使用redis作为消息队列的用法
- Redis批量删除key的小技巧,你知道吗?
- redis是如何存储对象和集合的
- Redis并发竞争key的解决方案详解
- 在windows上通过docker玩转redis的最新特性
- 从阿里、头条面试回来,面试官最喜欢问的Jvm和Redis你了解多少?
- 阿里架构师分享技术干货Spring+Redis+SpringBoot+Nginx等实践