介绍
Redis(Remote Dictionary Server)是一个使用C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。
NoSQL(Not Only SQL ),意即"不仅仅是SQL"。是区别传统关系型数据库(MySQL、Oracle)的非关系型数据库。NoSQL数据库大致分为以下几类:
类型 | 代表 | 特点 |
列存储 | Hbase、Cassandra | 按列存储数据,最大的特点是方便存储结构化和半结构化的数据,方便做数据压缩。 |
文档类型 | MongoDB | 文档存储一般用类似json的格式存储,存储的内容是文档型的。 |
key-value存储 | Redis、memcache | 可以通过key快速查询到其value |
图存储 | Neo4j | 图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。 |
对象存储 | db4o、Versant | 通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。 |
Xml数据库 | BerkeleyDB | 高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath。 |
Redis和memcache都是典型的K-V数据库,它们的区别主要有以下几点:
功能 | Redis | memcache |
数据类型 | String、Hash、List、Set、Sorted Set | 单一 |
持久化 | 支持(RDB、AOF、混合模式) | 不支持 |
主从同步 | 支持 | 不支持 |
分片 | 支持 | 不支持 |
正是因为Redis功能比memcache更加强大和丰富,所以在实际工作中往往会选择Redis。
Redis性能
单实例Redis能支持10W+的QPS(Query Per Second)
Redis之所以有这么快,主要有以下几个原因:
- 纯内存操作,不受硬盘I/O的限制
- 采用单线程模式,由一个线程对客户端的网络请求进行处理(并不是一个Redis服务只有一个线程),避免了频繁的上下文切换和锁竞争
- 多路I/O复用,非阻塞IO。复用是指复用同一个线程,多路是指多个请求。当某个请求的socket可读或者可写时,这个线程就会去处理那个请求。处理完成后会继续等待下一个socket可读或者可写。
数据类型
- String:最基本的数据类型,Redis没有直接使用C语言传统的字符串表示方法(以空字符结尾的字符数组),而是自己构建了简单动态字符串(Simple Dynamic String, SDS)的抽象类型,并将SDS作为Redis默认字符串表示。String是二进制安全的,可以包含任意类型的数据,最大为512MB。定义的结构体如下:
struct sdshdr {
int len; //记录buf数组中已使用的字节数量,等于SDS所保存的字符串的长度
int free; //记录buf数组中未使用的字节数量
char buf[]; //字节数组,用于保存字符串
}
- 基本操作如下:
set key value #存储k-v键值对
set count 1
get key #根据key获取value
get count
incr num #将数字类型value自增一
incr count
- Hash:即字典。这里 Value 存放的是结构化的对象,例如单个商品信息,用户权限信息等。
hmset key [field value] #存入一个对象(Hash)
hmset student name "zhangsan" age 24
hget key field #获取对象中某一字段的值
hget student name
hset key field value #给对象的某个属性赋值(属性如果不存在则新增)
hset student name "lisi"
- List:Redis使用双向链表实现了List,可以轻松地实现最新消息排行、消息队列等功能。
lpush key value [value ...] #从左边(头部)往List中添加元素,同理还有rpush
lpush testlist "java"
lrange key start stop #从左边(头部)开始取List中的元素
lrange testlist 0 10
- Set:放的是一堆不重复值的集合,是通过哈希表实现的。
sadd key member [member ...] #向Set中添加元素
sadd testset "java"
smembers key #查看Set中元素
smembers testset
- Sorted Set:有序集合,集合里是带有权重的元素,相比于Set里的元素多了一个权重score,使得集合中的元素能够按 score 进行有序排列。
zadd key score member #向Sorted Set中添加元素
zadd testzset 3 "java"
zrange key start stop [WITHSCORES] #查看Sorted Set中的元素
zrange testzset 0 10 WITHSCORES
- HyperLogLog:Redis 2.8.9新增。用来做基数统计,得到的基数估计的是误差范围内的估算值。HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
pfadd key element [element ...] #添加元素
pfadd testhyperloglog "java"
pfcount key #返回估算值
pfcount testhyperloglog
- Geo:Redis 3.2新增。用于存储地理位置信息,主要用于添加、删除地理位置信息、计算两个坐标点的距离、获取指定坐标,固定范围内坐标点的集合等。
geoadd key longitude latitude member [longitude latitude member ...] #添加地理位置信息
geoadd testgeo 116.395645 39.929986 beijing
geopos key member [member ...] #获取地理坐标
geopos testgeo beijing
Redis单个操作均为原子操作
持久化
Redis持久化有三种方式:RDB、AOF、RDB-AOF混合模式。
- RDB(Redis DataBase):Redis默认的持久化方案,实际上是指把某个时刻内存中的数据生成快照,以dump.rdb文件的形式存在磁盘上,Redis重启时会根据dump.rdb文件恢复数据。redis.conf中有快照生成的策略
save 900 1 # 900秒内至少有1条数据被改变
save 300 10 # 900秒内至少有10条数据被改变
save 60 10000 # 60秒内至少有10000条数据被改变
- 如果想要禁用RDB,只需要在redis.conf中加入
save ""
即可。除了配置之外,Redis还提供的指令来手动生成快照:save和bgsave。save以阻塞的方式生成快照,生成快照过程中由于阻塞了Redis服务进程,此时Redis将无法接收客户端的请求。bgsave则是fork一个子进程生成快照,不会阻塞Redis服务进程,redis.conf配置文件中采用的bgsave。除了根据配置文件自动触发持久化外,还有以下几种情况会自动触发持久化:主从复制时,主节点自动触发、执行Debug Reload、执行Shutdown且没有开启AOF。 - AOF(Append Only File):记录除了查询以外的所有命令,以Append的形式追加到AOF文件中。AOF方式默认是关闭的,在redis.conf中
appendonly no #需要把no改成yes
appendfilename "appendonly.aof" #默认的AOF文件名
appendfsync everysec #写入AOF的触发条件,可选值有三个always、everysec、no,分别表示每次修改都写入AOF、每秒写入AOF、由操作系统决定何时写入,一般是等待缓冲区被填满时写入
模式 | 优点 | 缺点 |
RDB | 全量数据快照、体积小、恢复快 | 无法保存最近一次持久化之后的数据 |
AOF | 可读性高,适合保存增量数据,数据不易丢失 | 文件体积大、恢复时间长 |
- RDB-AOF混合模式:为了结合两种持久化方式的优点,Redis4.0之后推出了RDB-AOF混合模式,并且作为默认配置。即AOF文件中前半段是RDB格式的全量数据,后半段是aof格式的Redis指令。用bgsave做全量持久化,用aof做增量持久化。这样既能最大限度的减少数据丢失,又能在Redis重启后迅速恢复数据。