Redis数据库
一、NoSQL简介
NoSQL,泛指非关系型的数据库,有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的的统称。
- SQL (Structured Query Language) 数据库,指关系型数据库。主要代表:SQL Server,Oracle,MySQL,PostgreSQL。存储数据时,需要预先定义表,字段–关系表
- NoSQL(Not Only SQL)泛指非关系型数据库。主要代表:MongoDB,Redis,CouchDB。无表无关联
关系数据库瓶颈
-
高并发读写需求
针对网站类用户的并发性访问非常高,而一台数据库的最大连接数有限,且硬盘I/O有限,其不能满足很多人同时连接
-
海量数据的高效率读写
网站每天产生的数据量是巨大的,对于关系型数据库来说,在一张包含海量数据的表中查询,效率是非常低的
二、Redis简介
1、Redis是什么?
REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
2、特点
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
3、优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
三、Redis安装
1、解压
将redis的tar包发送到Linux中,并解压: tar -zxvf redis-3.0.7.tar.gz
2、make指令
cd
指令切换到解压目录中,然后执行指令:make
-
执行make的时候,如出现异常:
-
异常一:
make[2]: cc: Command not found
异常原因:没有安装gcc
解决方案:yum install gcc
-
异常二:
zmalloc.h:51:31: error: jemalloc/jemalloc.h: No such file or directory
异常原因:一些编译依赖或原来编译遗留出现的问题
解决方案:make distclean。清理一下,然后再make。
-
3、make install
安装,执行指令:make install
执行make test测试
4、启动服务
-
第一种:前台模式,默认配置启动(默认端口6379)
直接执行指令:redis-server
-
第二种:守护进程(后台)模式,指定配置文件启动
-
在redis解压根目录中找到配置文件模板(redis.conf),复制到如下位置:
cp redis.conf /usr/local/redis_conf/redis.conf
-
通过vi命令修改
daemonize yes #守护进程模式启动 -- 后台 port 7000 #端口 也可以不改 pidfile ./redis.pid #进程id存储位置 logfile ./redis.log #日志文件存储位置 dir /usr/local/redis_conf/ #工作目录 rdb、aof文件存储位置
-
然后执行
redis-server redis.conf
-
5、连接Redis
执行指令:
redis-cli
连接端口为6379 Host为127.0.0.1的redis服务器redis-cli -p 7000 -h 192.168.1.103
连接端口为7000 Host为192.168.1.103的redis服务器
6、关闭服务
redis-cli连接了redis服务器后,可以通过shutdown
指令关闭连接,并关闭服务
或在命令行中执行 redis-cli -p 7000 shutdown
如果只想关闭连接(客户端),在redis命令中,按Ctrl+c
即可,此时服务不会被关闭
四、Redis数据类型
Redis支持物种数据类型:string(字符串)、list(列表)、set(集合)、zset(有序集合) 和hash(哈希)。
1、string(字符串)
命令 | 说明 | 示例 |
---|---|---|
set | 设置一个key/value | set name aaa |
get | 根据key获得对应的value | get name (keys * / keys n*) |
mset | 一次设置多个key value | mset age 18 salary 3000 |
mget | 一次获得多个key的value | mget name age |
getset | 获得原始key的值,同时设置新值 | getset age 20 |
del | 删除key-value | del name |
strlen | 获得对应key存储value的长度 | strlen name |
append | 为对应key的value追加内容 | appdend name 123 |
getrange | 截取value的内容,对原始的值没有影响 | getrange name 0 2 |
setex | 设置一个key存活的有效期(秒) | setex name 10 tom |
psetex | 设置一个key存活的有效期(毫秒) | psetex course10000 redis |
setnx | 只有当这个key不存在时等效set操作 not exist | sexnx birth 2020-2-2 |
msetnx | 可以同时设置多个key,在key不存在时有效 | msetnx course mysql duration 4 |
decr | 进行数值类型的-1操作 | decr age |
decrby | 根据提供的数据进行减法操作 | decrby age 3 |
incr | 进行数值类型的+1操作 | incr age |
incrby | 根据提供的数据进行加法操作 | incrby age 3 |
incrbyfloat | 根据提供的数据加入浮点数 | incrbyfloat age 3.5 |
2、list(列表)
命令 | 说明 | 示例 |
---|---|---|
lpush | 将某个值加入到一个key列表头部 | lpush users tom |
lpushx | 同lpush,但是必须要保证这个key存在 | lpushx users jack |
rpush | 将某个值加入到一个key列表末尾 | rpush users linda |
rpushx | 同rpush,但是必须要保证这个key存在 | rpushx users james |
lpop | 返回和移除列表的第一个元素 | lpop users |
rpop | 返回和移除列表的最后一个元素 | rpop users |
lrange | 获取某一个下标区间内的元素 | lrange users 0 3 lrange users 0 -1 |
llen | 获取列表元素个数 | llen users |
lset | 设置某一个位置的元素(替换已有的某个值) | lset users 2 andy |
lindex | 获取某一个位置的元素 | lindex users 2 |
lrem | 从列表头起,删除对应个数的指定元素 | lrem users 2 james |
ltrim | 保留列表中特定区间内的元素,将其它的元素删除 | ltrim users 1 3 |
linsert | 在某一个元素之前,之后插入新元素 | linsert users before/after jack Macle |
3、set(集合)
set无序集合,且不允许有相同的元素
命令 | 说明 | 示例 |
---|---|---|
sadd | 为集合添加元素 | sadd st tom |
smembers | 显示集合中所有元素 无序 | smembers st |
scard | 返回集合中元素的个数 | scard st |
spop | 随机返回并移除一个元素 | spop st |
smove | 从一个集合中向另一个集合移动元素 | smove st1 st2 tom |
srem | 从集合中删除一个元素 | srem st tom |
sismember | 判断一个集合中是否含有这个元素 | sismember st tom |
srandmember | 随机返回元素,对原始数据没有影响 | srandmember st |
sdiff | 减去两个集合中共有的元素 求差集 | sdiff st1 st2 |
sinter | 求交集 | sinter st1 st2 |
sunion | 求并集 | sunion st1 st2 |
4、zset(有序集合)
命令 | 说明 | 示例 |
---|---|---|
zadd | 添加一个有序集合元素,根据元素的score排序 | zadd salary 3000 tom 2000 jack |
zcard | 返回集合的元素个数 | zcard salary |
zrange | 返回一个范围内的元素 | zrange salary 1 2 withscores |
zrangebyscore | 按照分数查找一个范围内的元素 | zrangebyscore salary 1000 2000 |
zrank | 返回对应元素的排名 | zrank salary tom |
zrevrank | 返回对应元素倒序排名 | zrevrank salary tom |
zscore | 显示某一个元素的分数 | zscore salary tom |
zrem | 移除某一个元素 | zrem salary tom |
zincrby | 给某个特定元素加分 | zincrby salary 100 tom |
5、hash(哈希)
命令 | 说明 | 示例 |
---|---|---|
hset | 设置一个key/value对 | hset user name tom |
hget | 获得一个key对应的value | hget user name |
hgetall | 获得所有的key/value对 | hgetall user |
hdel | 删除某一个key/value对 | hdel user name |
hexists | 判断一个key是否存在 | hexists user name |
hkeys | 获得所有的key | hkeys user |
hvals | 获得所有的value | hvals user |
hmset | 设置多个key/value | hmset user name tom gender true |
hmget | 获得多个key的value | hmget user name age |
hsetnx | 设置一个不存在的key的值 | hsetnx user salary 4000 |
hincrby | 为value进行加法运算 | hincrby user age 3 |
hincrbyfloat | 为value加入浮点值 | hincrbyfloat user age 3.5 |
五、Redis持久化
1、什么是持久化
持久化的含义就是把内存的数据保存到磁盘中(可存储的设备),以便数据的重用。
- 存:读内存中Redis的数据->存储到磁盘中(内存->磁盘)
- 读:读磁盘的文件->内存中(磁盘->内存)
redis是内存数据库,它把数据存储在内存中,这样在加快读取速度的同时也对数据库的安全性产生了新的问题,即当服务器发生故障的时候,redis数据库中的数据丢失问题。
为了解决这个问题,redis提供了持久化功能:
- RDB持久化(snapshotting快照 - 原理:将Redis在内存中的数据记录定时dump到磁盘中)
- AOF持久化(append only file - 原理:将Redis数据库的操作日志以追加的方式写到磁盘)
简单来说,就是讲内存中的数据写到磁盘中,当redis重启后,数据可以恢复
2、RDB持久化
1、开发步骤
编辑redis.conf文件:
save 900 1 #900秒内超过1个key被修改
save 300 10 #300秒内超过10个key被修改
save 60 10000
dbfilename dump.rdb #快照文件名
stop-writes-on-bgsave-error yes #快照失败后是否继续写操作
rdbcompression yes #是否压缩快照文件
2、运行原理
- 在某些时刻(满足RDB持久化的时刻),Redis通过fork产生子进程,一个父进程的快照(副本),有当前父进程的所有数据。
- 父进程继续处理client请求,子进程负责将快照写入到临时文件(dump.rdb)
- 子进程写完后,用临时文件替换原来的快照文件,然后子进程退出
3、RDB触发方式
- 1、 根据save 900 1 ,满足时间自动触发
- 2 、在redis控制台,手动执行bgsave,子进程处理
- 3、在redis控制台,手动执行save,父进程处理,会造成进程阻塞,使服务器不能处理客户端请求,但是处理速度会更快
- 4、通过shutdown关闭redis,自动触发
4、RDB注意事项
- 如果系统发生崩溃,则会丢失最近一次rdb之后的数据,如果不能接受,不建议使用
- 如果数据量过大,则创建子进程的时间长,导致redis卡顿,要谨慎设置save参数的时间间隔
- 将生成的快照文件,留在原地,则可以在重启redis后,回复数据状态
- 将生成的快照文件,赋值到其他redis服务器中,可以把数据移植过去
3、AOF持久化
Append-Only-File(AOF):是将操作命令保存在文件中。
1、运行机制
Redis将每一个写操作(执行成功),写入到aof文件,记录所有成功的数据改动行为,redis重启执行一次aof文件,即可恢复数据,也可以做数据移植
注意: 重启时,如果rdb和aof同时存在,以aof为主
2、AOF配置
appendonly yes #启动AOF机制
# appendfsync always #每次收到写命令就立即强制写入磁盘,保证完全的持久化,但产生极大的IO开销(不推荐使用)
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中(推荐使用)
# appendfsync no #完全依赖os,虽然基本不对redis性能产生影响,但操作系统的缓存区满时,会阻塞redis(不推荐使用)
appendfilename "appendonly.aof" # 设置aof文件名
3、AOF细节
- AOF文件会不断增长,在极端情况下(比快照文件大几倍),会对硬盘空间造成压力
- Redis重启数,执行非常大的AOF文件,时间很长
- AOF时间间隔小,数据更安全,理论上最多丢失1秒的数据
注意:
- r如果当前数据量巨大,则子进程创建过程会很耗时
- 在替换aof文件时,如果旧aof很大,则删除它也很耗时
4、RDB与AOF比较
- RDB体量小,AOF体量大
- RDB同步时间间隔大,AOF时间间隔小,所以AOF更安全
- RDB有更快的恢复速度,可以用来做数据恢复。RDB每次快照都会重新记录整个数据集的所有信息。RDB恢复速度更快,可以最大化redis性能
- 通过使用RDB和AOF,用户可以在重启或系统崩溃后保留数据,但随着负载量变大和数据安全越来越重要,可以使用redis的复制特性来更好的数据安全保障
RDB用来做数据备份,并且要求数据恢复快,对数据一致性要求不高时。
5、AOF重写
1、重写设置
AOF采用文件追加的方式持久化数据,这样文件会越来越大,为了避免这种情况。
-
手动发送bdwriteaof命令,会创建子进程,通过移除aof文件中的冗余命令来重写aof文件,替换掉旧的、大体量的aof文件
-
也可以设置:
auto-aof-rewrite-percenteage 100
auto-aof-rewrite-min-size 64mb
在体量超过64mb,且比上次重写后的体量增加了100%时自动触发。
2、重写原理
Redis将AOF重写程序放到子程序(后台)里执行。
好处:
- 子进程进行AOF重写期间,主进程可以继续处理命令请求:
- 子进程带有主进程的数据副本,使用子进程而不是线程,保证数据的安全性。
产生的问题:
- 子进程在进行AOF重写期间,服务器主进程还要继续处理命令请求,而新的命令可能对现有数据进行修改,会导致当前数据库的数据和重写后的AOF文件中的数据不一致。
**解决方案 **
- Redis增加了一个AOF重写缓存,这个缓存在fork出子进程之后开始启用,Redis服务器主进程在执行完命令之后,会同时将这个鞋命令追加到AOF文件和AOF重写缓存区。
在子进程进程AOF重写时,主进程需要执行以下三个工作:
- 执行client发来的命令请求
- 将写命令追加到现有的AOF文件中
- 将写命令追加到AOF重写缓存中
六、Redis主从
1、简介
在高负载和数据要求高完整性时,数据的复制是不可或缺的。一个Redis主服务器,并为其关联多个从服务器,主服务器会将自己的数据状态不断的同步给从服务器,即,从服务器持有主服务器最新的数据副本,则为数据的完整性提供了进一步的保证,而且所有的读取操作都可均衡的负载到多个从服务器中,主服务器主要负责写操作。则主从多个服务器实现读写分离,提供更好的数据完整性,和更强的负载能力
2、主从配置
开启两个redis服务器,一个主服务器,一个从服务器,只需在从服务器的配置添加依据配置
slaveof host port 比如:slaveof 192.168.1.103 7000 #主服务器的ip
则如上配置将当前的redis服务器设置为(192.168.1.103:7000)的从服务器
- 这样,主服务器的所有数据会在初始接收到从服务器的连接时发送所有数据到从服务器。之后每次主服务器执行一个写操作,都会发送到从服务器
- 可以设置多台主从服务器,主服务器只负责写,从服务器负责读