Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。
总结来说,使用Redis的好处如下:
- 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
- 支持丰富数据类型,支持
string,hash,list,set,zset
- 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行
- 丰富的特性,可用于缓存,消息,计数,按key设置过期时间,过期后将会自动删除
- 单线程,预防多线程的竞态问题
一、Redis的使用
1.redis数据结构 – strings
set mystr "hello world!" //设置字符串类型
get mystr //读取字符串类型
我们还可以通过字符串类型进行数值操作:
127.0.0.1:6379> set mynum "2"
OK
127.0.0.1:6379> get mynum
"2"
127.0.0.1:6379> incr mynum
(integer) 3
127.0.0.1:6379> get mynum
"3"
在遇到数值操作时,redis会将字符串类型转换成数值。
由于INCR
等指令本身就具有原子操作的特性,所以我们完全可以利用redis的INCR、INCRBY、DECR、DECRBY
等指令来实现原子计数的效果,假如,在某种场景下有3个客户端同时读取了mynum的值(值为2),然后对其同时进行了加1的操作,那么,最后mynum的值一定是5。不少网站都利用redis的这个特性来实现业务上的统计计数需求。
如果有多客户同时执行setnx
,只有一个能设置成功,可做分布式锁
set
命令也支持批量处理,mset/mget
批量设置和批量获取。批量操作提高了执行效率,否则一批次的n次查询需要发起n次请求。
2.redis数据结构 – 哈希
Hash存的是字符串和字符串值之间的映射,特别适合存储对象,比如一个用户要存储其全名、姓氏、年龄等等,就很适合使用哈希(此处如果用String类型就会占用过多的key空间)。
-
hset key field value
单个赋值 -
hmset key field value [filed value]...
批量赋值
//建立哈希,并赋值
127.0.0.1:6379> HMSET user:001 username antirez password P1pp0 age 34
OK
//列出哈希的内容
127.0.0.1:6379> HGETALL user:001
1) "username"
2) "antirez"
3) "password"
4) "P1pp0"
5) "age"
6) "34"
//更改哈希中的某一个值
127.0.0.1:6379> HSET user:001 password 12345
(integer) 0
//再次列出哈希的内容
127.0.0.1:6379> HGETALL user:001
1) "username"
2) "antirez"
3) "password"
4) "12345"
5) "age"
6) "34"
在一般应用场景中,用户信息缓存化,可以有三种解决方案,1、set
存储,2、对象信息序列化存储,3、hset
存储,用户信息不经常修改的情况可用2,value值不大的情况可以用3.
3.redis数据结构 – lists
首先要明确一点,redis中的lists在底层实现上并不是数组,而是链表,因此是增删改快,定位较慢。
lists的常用操作包括LPUSH、RPUSH、LRANGE
等。我们可以用LPUSH
在lists的左侧插入一个新元素,用RPUSH
在lists的右侧插入一个新元素,用LRANGE
命令从lists中指定一个范围来提取元素。
//新建一个list叫做mylist,并在列表头部插入元素"1"
127.0.0.1:6379> lpush mylist "1"
//返回当前mylist中的元素个数
(integer) 1
//在mylist右侧插入元素"2"
127.0.0.1:6379> rpush mylist "2"
(integer) 2
//在mylist左侧插入元素"0"
127.0.0.1:6379> lpush mylist "0"
(integer) 3
//列出mylist中从编号0到编号1的元素
127.0.0.1:6379> lrange mylist 0 1
1) "0"
2) "1"
//列出mylist中从编号0到倒数第一个元素
127.0.0.1:6379> lrange mylist 0 -1
1) "0"
2) "1"
3) "2"
4.redis数据结构 – set集合
Redis的集合,是一种无序的集合,集合中的元素没有先后顺序。集合相关的操作也很丰富,如添加新元素、删除已有元素、取交集、取并集、取差集等。
//向集合myset中加入一个新元素"one"
127.0.0.1:6379> sadd myset "one"
(integer) 1
127.0.0.1:6379> sadd myset "two"
(integer) 1
//列出集合myset中的所有元素
127.0.0.1:6379> smembers myset
1) "one"
2) "two"
//判断元素1是否在集合myset中,返回1表示存在
127.0.0.1:6379> sismember myset "one"
(integer) 1
//判断元素3是否在集合myset中,返回0表示不存在
127.0.0.1:6379> sismember myset "three"
(integer) 0
//新建一个新的集合yourset
127.0.0.1:6379> sadd yourset "1"
(integer) 1
127.0.0.1:6379> sadd yourset "2"
(integer) 1
127.0.0.1:6379> smembers yourset
1) "1"
2) "2"
//对两个集合求并集
127.0.0.1:6379> sunion myset yourset
1) "1"
2) "one"
3) "2"
4) "two"
使用场景:标签,社交,查询有共同兴趣爱好的人,智能推荐
5.redis数据结构-zset有序集合
同无序集合一样,存储string类型且不能重复。每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
redis 127.0.0.1:6379> ZADD key 1 redis
(integer) 1
redis 127.0.0.1:6379> ZADD key 2 mongodb
(integer) 1
redis 127.0.0.1:6379> ZADD key 3 mysql
(integer) 1
redis 127.0.0.1:6379> ZADD key 3 mysql
(integer) 0
redis 127.0.0.1:6379> ZADD key 4 mysql
(integer) 0
redis 127.0.0.1:6379> ZRANGE key 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "2"
5) "mysql"
6) "4"
常用于排行榜,如视频网站需要对用户上传视频做排行榜,或点赞数
6.redis的全局命令
- 查看所有键:
keys *
,也可以用*
进行模糊匹配。 - 键总数
dbsize
如果存在大量键,线上禁止使用此指令 - 检查键是否存在:
exists keyName
存在返回1,不存在返回0 - 删除键:
del keyName
返回删除键个数,删除不存在键返回0 - 键过期:
expire keyName seconds
- 键的数据结构类型:
type key
返回string,键不存在返回nil
Redis的命令很多,提供如下网站可以作为工具网站进行查阅:
source:【Redis 命令参考】
二、Redis持久化机制
Redis是一个支持持久化的内存数据库,为了防止数据丢失Redis需要经常将内存中的数据同步到磁盘来保证持久化,它提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。
1.RDB(Redis DataBase)
简而言之,就是在不同的时间点,将redis存储的数据生成快照并存储到磁盘等介质上;
Redis默认为该方式,内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb
(如果需要恢复数据,只需将备份文件dump.rdb
移动到 redis 安装目录并启动服务即可)。可以通过配置设置自动做快照持久化的方式。配置redis在n秒内如果超过m个key被修改就自动做快照,下面是默认的快照保存配置。
save 900 1 #900秒内如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000 #60秒内容如超过10000个key被修改,则发起快照保存
client 也可以使用save
或者bgsave
命令手动通知redis做一次快照持久化。save
操作是在主线程中保存快照的,由于redis是用一个主线程来处理所有 client的请求,这种方式会阻塞所有client请求,不推荐使用。
RDB利弊 | 原因 |
---|---|
优点1 | 压缩后的二进制文,适用于备份、全量复制,用于灾难恢复 |
优点2 | 大数据量时,加载RDB恢复数据远快于AOF方式 |
缺点1 | 无法做到实时持久化,每次都要创建子进程,频繁操作成本过高 |
缺点2 | 保存后的二进制文件,存在老版本不兼容新版本rdb文件的问题 |
2.AOF(Append Only File)
AOF则是换了一个角度来实现持久化,那就是将redis执行过的所有写指令记录下来,在下次redis重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了,相关配置如下:
appendonly no # redis默认关闭AOF机制,可以将no改成yes实现AOF持久化
appendfsync always # 每次有数据修改发生时都会写入AOF文件。
appendfsync everysec # 每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync no # 从不同步。高效但是数据不会被持久化。
具体操作方式:如何从AOF恢复数据?1. 设置appendonly yes
;2. 将appendonly.aof
放到dir
参数指定的目录;3. 启动Redis,Redis会自动加载appendonly.aof
文件。
其实RDB和AOF两种方式也可以同时使用,在这种情况下,如果redis重启的话,则会优先采用AOF方式来进行数据恢复,这是因为AOF方式的数据恢复完整度更高。如果你没有数据持久化的需求,也完全可以关闭RDB和AOF方式,这样的话,redis将变成一个纯内存数据库,就像memcache一样。
重启时恢复加载AOF与RDB顺序及流程:
- 当AOF和RDB文件同时存在时,优先加载AOF
- 若关闭了AOF,加载RDB文件
- 加载AOF/RDB成功,redis重启成功
- AOF/RDB存在错误,redis启动失败并打印错误信息
3. Redis主从下的持久化方案设计
- Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
- 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
- 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
- 尽量避免在压力很大的主库上增加从库
- 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...。这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。