Redis介绍
开源免费的高性能key-value数据库
Redis的应用场景
Redis作者提出的九个应用场景
-
取最新N个数据的操作
比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取- 使用LPUSH latest.comments<ID>命令,向list集合中插入数据
- 插入完成后再用LTRIM latest.comments 0 5000命令使其永远只保存最近5000个ID
Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
-
排行榜应用,取TOP N操作
这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可
利用有序集合的性质 -
需要精准设定过期时间的应用
-
Uniq操作,获取某段时间所有数据排重值
使用Redis的set数据结构,只需要不断地将数据往set中扔就行了,set都保证集合中的元素都是唯一的 -
实时系统,反垃圾系统
-
Pub/Sub构建实时消息系统
-
计数器应用
-
构建队列系统
使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统
Mysql 有自己的缓存机制 ,为什么还要用Redis缓存Mysql数据
![](https://img.haomeiwen.com/i9358011/65f5504fc7dfb48c.jpg)
- 这个缓存是本地缓存,如果有多台服务器,sql语句会随机发送给其中一台,无法保证相同的请求会发送给同一台,这样本地缓存命中率就比较低,本地缓存(即查询缓存)就没有什么用了
- 从查询缓存中取出结果或者将查询结果添加进查询缓存中,会带来额外性能消耗
- 当表的结构或内容发生变化时,使用这个表的缓存查询将不再有效,查询缓存值的相关条目将被清空。常见修改表结构和表内容的语句,如delete、insert、altert able很多。使用redis作为缓存将受这个影响很小,因为它是基于键值对保存缓存的,只有key对应的缓存内容发生变化,才会受到影响,其他key对应缓存内容发生变化对其几乎是没有影响的
数据类型
支持五种数据类型
- 字符串 (String)
- 哈希 (Hash)
- 列表 (List)
- 集合 (Set)
无序不重复 - 有序集合(sorted set)
在Set的基础上每个元素都会关联一个double类型的分数。redis通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复
Redis和Memcached的区别
-
Redis支持的数据类型更丰富
-
Redis支持持久化,满足条件时会进行持久化
比如900秒内进行1次修改 300秒内进行10次修改 60秒内进行10000次修改就会进行一个持久化将数据保存在磁盘中
Redis提供两种持久化的方式 AOF RDB 默认是RDB
Memcached把数据全部存储在内存中,断电后会挂掉 -
IO模型不同 (待补充,下次分享讲)
Redis:单线程非阻塞IO复用 模型
Memcached:多线程非阻塞IO复用 -
集群管理的不同 (待补充,下次分享讲)
String数据类型的底层实现
String的底层实现为SDS(简单动态字符串)
数据结构:
struct sdshdr {
int len;
int free;
char buf[];
};
![](https://img.haomeiwen.com/i9358011/f372278d37e02d5a.png)
free
:未使用的空间len
:保存字符串的长度,'\0'不做统计buf
:char类型数组
SDS与C字符串的区别
-
SDS常数复杂度获取字符串长度,直接从len属性中读取,时间复杂度为O(1)
C字符串不记录自身长度的长度信息,获取字符串的长度必须遍历整个字符串,时间复杂度为O(n) -
Redis通过空间分配策略完全杜绝了发生缓冲区溢出的可能性。当SDS API需要对SDS进行修改时,API首先会检查SDS的空间是否满足修改所需的要求,如果不满足,API会自动将SDS的空间扩展至执行所需的大小,然后在执行实际的修改操作
C字符串执行某些操作时若没有人工分配足够的内存,将会造成缓冲区溢出 -
减少修改字符串时带来的内存重分配次数
-
空间预分配
当需要对SDS进行空间扩展时,程序不仅会为SDS分配修改所需要的空间,还会为SDS分配额外的未使用空间
分配策略- SDS的长度小于1MB,程序分配和len属性同样大小的未使用的空间
即如果进行修改以后,SDS的len变成13字节,那么程序也会也会分配13字节未使用空间,实际长度13byte+13byte+1byte - SDS的长度大于1MB,程序将会分配1MB的未使用空间
即如果进行修改以后,SDS的len变成2MB,那么程序也会会分配1MB未使用空间,实际长度30MB +1MB+1byte
- SDS的长度小于1MB,程序分配和len属性同样大小的未使用的空间
-
惰性空间释放
当SDS的API需要缩短SDS保存的字符串时,程序不会立即使用内存重分配立即回收缩短后多出来的字节,而是使用free属性将这些字节的数量记录起来,等待将来使用。如果需要真正释放SDS的未使用空间。可以通过调用sdsfree API
-
好处:减少内存分配次数
-
二进制安全
SDS的API都是二进制安全的,所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,数据在写入时是什么样,它被读取时就是什么样的 -
兼容部分C字符串函数
通过遵循C字符串以空字符串结尾的惯例,SDS在有需要的时候可以重用<string.h>函数库,避免了不必要的代码重复
参考:
《Redis设计与实现》
《高性能MySQL》
网友评论