前言:
我们将在文章中探讨其数据结构、应用场景、持久化方式以及如何在实际应用中提高性能。
什么是Redis
Redis是一种基于键值对(key-value)的NoSQL数据库。
Redis 常被用来做分布式的高速缓存,相比较我们常规使用的Mysql、SqlServer等数据库,Redis的最大特点在于数据读写全部在内存中进行,进而带来极大的效率优势。相比较其他的内存键值存储系统如Memcached, Redis支持更多的数据结构,极大的提升了使用的易用性。同时Redis采用典型的CS架构, 并且有着非常丰富的不同语言客户端支持。
Redis 数据结构
Redis中支持string(字符串)、hash(哈希)、 list(列表)、set(集合)、zset(有序集合)、Bitmaps(位图)、 HyperLogLog、GEO(地理信息定位) 等多种数据结构,因此 Redis可以满足很多的应用场景。本文主将常用的五种数据结构string(字符串)、hash(哈希)、 list(列表)、set(集合)、zset(有序集合)
String
字符串最基础的数据结构。字符串类型的值实际可以是字符串(简单的字符串、复杂的字符串(例如JSON、XML))、数字 (整数、浮点数),甚至是二进制(图片、音频、视频),但是值最大不能超过512MB.
使用场景: 缓存、计数器、分布式锁等
常用命令:
哈希Hash
使用场景: 存储具有一定结构化的数据
常用命令:
列表List
使用场景: 消息队列,文章列表
常用命令:
set
使用场景: 标签(tag),共同关注
常用命令:
zset(Sorted Set)
使用场景: 排行榜,按序执行的任务队列
常用命令:
Redis 为什么这么快
单机的Redis可以⽀撑每秒十几万的并发,相对于MySQL来说,性能是MySQL的⼏⼗倍。速度快的原因主要有⼏点:
-
完全基于内存操作
-
使⽤单线程(6.0采用多线程),避免了线程切换和竞态产生的消耗
redis6.0之后对多线程的支持有了相当大的改进。Redis 引入了一个新的特性,称为
I/O threads
。I/O threads
在处理客户端请求和响应时,使用多个线程,以提高性能。
这些线程并不会处理命令的执行(Redis 在这方面仍然是单线程的);它们只负责处理客户端连接的读写操作。 -
基于⾮阻塞的IO多路复⽤机制
-
C语⾔实现,优化过的数据结构,基于⼏种基础的数据结构,redis做了⼤量的优化,性能极⾼
什么是IO多路复用
这里引入知乎高赞回答方便理解,想深入了解请自行百度
假设你是一个老师,让30个学生解答一道题目,然后检查学生做的是否正确,你有下面几个选择:
- 第一种选择:按顺序逐个检查,先检查A,然后是B,之后是C、D。。。这中间如果有一个学生卡住,全班都会被耽误。(阻塞IO模型)
- 第二种选择:你创建30个分身,每个分身检查一个学生的答案是否正确。 这种类似于为每一个用户创建一个进程或者线程处理连接。
- 第三种选择,你站在讲台上等,谁解答完谁举手。这时C、D举手,表示他们解答问题完毕,你下去依次检查C、D的答案,然后继续回到讲台上等。此时E、A又举手,然后去处理E和A。。。 (IO多路复用)
Redis的键淘汰机制
定期删除
redis 会将每个设置了过期时间的 key 放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的 key。
Redis 默认会每秒进行十次过期扫描(100ms一次),过期扫描不会遍历过期字典中所有的 key,而是采用了一种简单的贪心策略。
-
从过期字典中随机 20 个 key;
-
删除这 20 个 key 中已经过期的 key;
-
如果过期的 key 比率超过 1/4,那就重复步骤 1;
redis默认是每隔 100ms就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载。
惰性删除
所谓惰性策略就是在客户端访问这个key的时候,redis对key的过期时间进行检查,如果过期了就立即删除,不会给你返回任何东西。
定期删除可能会导致很多过期key到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,即当你主动去查过期的key时,如果发现key过期了,就立即进行删除,不返回任何东西。
本文中简单讲了下Redis的基本概念、数据类型、以及键淘汰机制,实际redis的功能点还有很多,我们下期文章继续讲下。