Redis
# 一、从NoSQL说起NoSQL是Not only SQL的缩写,大意为“不只是SQL”,说明这项技术是传统关系型数据库的补充而非替代。在整个NoSQL技术栈中MemCache、Redis、MongoDB被称为NoSQL三剑客。那么时代为什么需要NoSQL数据库呢?我们来做个对比:
对比 | 关系型数据库 | NoSQL数据库 |
---|---|---|
数据存储位置 | 硬盘 | 内存 |
数据结构 | 高度组织化结构化数据 | 没有预定义的模式 |
数据操作方式 | SQL | 所有数据都是键值对,没有声明性查询语言 |
事务控制 | 严格的基础事务ACID原则 | CAP定理 |
所以NoSQL数据库的最大优势体现为:高性能、高可用性和可伸缩性。
二、Redis简介
Redis英文官网介绍:
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster.
Redis中文官网介绍:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
Redis命令参考文档网址:http://redisdoc.com
三、Redis安装
1. 下载并解压安装
下载
redis-4.0.2.tar.gz
到/opt
目录下解压到当前目录下
1
tar -zxvf redis-4.0.2.tar.gz
2. 安装C语言编译环境
1 | yum intall -y gcc-c++ |
3. 修改安装位置
1 | vim opt/src/Makefile |
4. 编译安装
1 | make #编译 |
5.启动Redis服务器
①默认启动
1 | [root@localhost ~]# /usr/local/redis/bin/redis-server |
停止Redis服务器
1 | /usr/local/redis/bin/redis-cli shutdown |
1 | 7239:M 07 Oct 19:00:53.208 # User requested shutdown... |
②定制配置项启动
[1]准备配置文件
cp /opt/redis-4.0.2/redis.conf /usr/local/redis/
[2]修改配置项
配置项名称 | 作用 | 取值 |
---|---|---|
daemonize | 控制是否以守护进程形式运行Redis服务器 | yes |
logfile | 指定日志文件位置 | “/usr/local/redis/redis.log” |
dir | Redis工作目录 | /usr/local/redis |
注意:/var/logs目录需要我们提前创建好
[3]让Redis根据指定的配置文件启动
格式
1 | redis-server文件路径 redis.conf文件路径 |
举例
1 | /usr/local/redis/bin/redis-server /usr/local/redis/redis.conf |
6.客户端登录
/usr/local/redis/bin/redis-cli -h 127.0.0.1 -p 6379
1 | 127.0.0.1:6379> ping |
关闭redis服务:/usr/local/bin/redis-cli -h IP地址 -p 端口号 shutdown
四、Redis五种常用数据结构
1.总体结构
KEY | VALUE |
---|---|
string | string |
list | |
set | |
hash | |
zset |
Redis中的数据,总体上是键值对,不同数据类型指的是键值对中值的类型。
2.string类型
Redis中最基本的类型,它是key对应的一个单一值。二进制安全,不必担心由于编码等问题导致二进制数据变化。所以redis的string可以包含任何数据,比如jpg图片或者序列化的对象。Redis中一个字符串值的最大容量是512M。
3.list类型
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。说明它的底层是基于链表实现的,所以它操作时头尾效率高,中间效率低。
2.set类型
Redis的set是string类型的无序集合。它是基于哈希表实现的。
3.hash类型
本身就是一个键值对集合。可以当做Java中的Map<String,Object>对待。
4.zset类型
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。
五、Redis命令行操作
1.基本操作
①切换数据库
1 | Redis默认有16个数据库。 |
②查看数据库长度
1 | 127.0.0.1:6379> dbsize |
2.KEY操作
1 | ●KEYS PATTERN |
2.string操作
1 | ●SET KEY VALUE [EX SECONDS] [PX MILLISECONDS] [NX|XX] |
3.list操作
1 | ●LPUSH key value [value ...] |
4.set操作
1 | ●SADD key member [member ...] |
5.hash操作
1 | ●HSET key field value |
6.zset操作
1 | ●ZADD key [NX|XX] [CH] [INCR] score member [score member ...] |
六、Redis持久化机制
Redis工作时数据都存储在内存中,万一服务器断电,则所有数据都会丢失。针对这种情况,Redis采用持久化机制来增强数据安全性。
1.RDB
①机制描述
每隔一定的时间把内存中的数据作为一个快照保存到硬盘上的文件中。Redis默认开启RDB机制。
②触发时机
[1]基于默认配置
1 | save 900 1 |
含义
配置 | 含义 |
---|---|
save 900 1 | 900秒内至少有一次修改则触发保存操作 |
save 300 10 | 300秒内至少有10次修改则触发保存操作 |
save 60 10000 | 60秒内至少有1万次修改则触发保存操作 |
[2]使用保存命令
save或bgsave
[3]使用flushall命令
这个命令也会产生dump.rdb文件,但里面是空的,没有意义,相当于删除所有数据。
[4]服务器关闭
如果执行SHUTDOWN命令让Redis正常退出,那么此前Redis就会执行一次持久化保存。
③相关配置
配置项 | 取值 | 作用 |
---|---|---|
save | “” | 禁用RDB机制 |
dbfilename | 文件名,例如:dump.rdb | 设置RDB机制下,数据存储文件的文件名 |
dir | Redis工作目录路径 | 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名 |
④思考
RDB机制能够保证数据的绝对安全吗?
2.AOF
①机制描述
根据配置文件中指定的策略,把生成数据的命令保存到硬盘上的文件中。一个AOF文件的内容可以参照下面的例子:
1 | *2 |
生成上面文件内容的Redis命令是:
1 | set num 10 |
②AOF基本配置
配置项 | 取值 | 作用 |
---|---|---|
appendonly | yes | 启用AOF持久化机制 |
no | 禁用AOF持久化机制[默认值] | |
appendfilename | “文件名” | AOF持久化文件名 |
dir | Redis工作目录路径 | 指定存放持久化文件的目录的路径。注意:这里指定的必须是目录不能是文件名 |
appendfsync | always | 每一次数据修改后都将执行文件写入操作,缓慢但是最安全。 |
everysec | 每秒执行一次写入操作。折中。 | |
no | 由操作系统在适当的时候执行写入操作,最快。 |
③AOF重写
对比下面两组命令:
AOF重写前 | AOF重写后 |
---|---|
set count 1 incr count incr count incr count |
set count 4 |
两组命令执行后对于count来说最终的值是一致的,但是进行AOF重写后省略了中间过程,可以让AOF文件体积更小。而Redis会根据AOF文件的体积来决定是否进行AOF重写。参考的配置项如下:
配置项 | 含义 |
---|---|
auto-aof-rewrite-percentage 100 | 文件体积增大100%时执行AOF重写 |
auto-aof-rewrite-min-size 64mb | 文件体积增长到64mb时执行AOF重写 |
实际工作中不要进行频繁的AOF重写,因为CPU资源和硬盘资源二者之间肯定是CPU资源更加宝贵,所以不应该过多耗费CPU性能去节省硬盘空间。
3.持久化文件损坏修复
Redis服务器启动时如果读取了损坏的持久化文件会导致启动失败,此时为了让Redis服务器能够正常启动,需要对损坏的持久化文件进行修复。这里以AOF文件为例介绍修复操作的步骤。
第一步:备份要修复的appendonly.aof文件
第二步:执行修复程序
/usr/local/redis/bin/redis-check-aof –fix /usr/local/redis/appendonly.aof
第三步:重启Redis
注意:所谓修复持久化文件仅仅是把损坏的部分去掉,而没法把受损的数据找回。
4.扩展阅读:两种持久化机制的取舍
①RDB
[1]优势
适合大规模的数据恢复,速度较快
[2]劣势
会丢失最后一次快照后的所有修改,不能绝对保证数据的高度一致性和完整性。Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑,但上述成立有条件,Linux也有优化手段
②AOF
[1]优势
选择appendfsync always方式运行时理论上能够做到数据完整一致,但此时性能又不好。文件内容具备一定可读性,能够用来分析Redis工作情况。
[2]劣势
持久化相同的数据,文件体积比RDB大,恢复速度比RDB慢。效率在同步写入时低于RDB,不同步写入时与RDB相同。
③RDB和AOF并存
Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整
RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份)、快速重启,而且不会有AOF可能潜在的bug,留着作为一个万一的手段。
④使用建议
如果Redis仅仅作为缓存可以不使用任何持久化方式。
其他应用方式综合考虑性能和完整性、一致性要求。
RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留save 900 1这条规则。如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。如果不开启AOF,仅靠Master-Slave Replication 实现高可用性能也不错。能省掉一大笔IO也减少了rewrite时带来的系统波动。代价是如果Master/Slave同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个Master/Slave中的RDB文件,载入较新的那个。新浪微博就选用了这种架构。
七、Redis事务控制
1.Redis事务控制的相关命令
命令名 | 作用 |
---|---|
MULTI | 表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。 |
EXEC | 执行MULTI后面命令队列中的所有命令。 |
DISCARD | 放弃执行队列中的命令。 |
WATCH | “观察“、”监控“一个KEY,在当前队列外的其他命令操作这个KEY时,放弃执行自己队列的命令 |
UNWATCH | 放弃监控一个KEY |
2.命令队列执行失败的两种情况
①加入队列时失败
1 | 127.0.0.1:6379> multi |
遇到了入队时即可检测到的错误,整个队列都不会执行。
②执行队列时失败
1 | 127.0.0.1:6379> multi |
错误在入队时检测不出来,整个队列执行时有错的命令执行失败,但是其他命令并没有回滚。
③Redis为什么不支持回滚
官方解释如下:
如果你有使用关系式数据库的经验, 那么 “Redis 在事务失败时不进行回滚,而是继续执行余下的命令”这种做法可能会让你觉得有点奇怪。以下是这种做法的优点: 1.Redis 命令只会因为错误的语法而失败(并且这些问题不能在入队时发现),或是命令用在了错误类型的键上面:这也就是说,从实用性的角度来说,失败的命令是由编程错误造成的,而这些错误应该在开发的过程中被发现,而不应该出现在生产环境中。 2.因为不需要对回滚进行支持,所以 Redis 的内部可以保持简单且快速。 有种观点认为 Redis 处理事务的做法会产生 bug , 然而需要注意的是, 在通常情况下, 回滚并不能解决编程错误带来的问题。 举个例子, 如果你本来想通过 INCR 命令将键的值加上 1 , 却不小心加上了 2 , 又或者对错误类型的键执行了 INCR , 回滚是没有办法处理这些情况的。
3.悲观锁和乐观锁
在使用WATCH命令监控一个KEY后,当前队列中的命令会由于外部命令的执行而放弃,这是乐观锁的体现。
悲观锁
认为当前环境非常容易发生碰撞,所以执行操作前需要把数据锁定,操作完成后释放锁,其他操作才可以继续操作。
乐观锁
认为当前环境不容易发生碰撞,所以执行操作前不锁定数据,万一碰撞真的发生了,那么放弃自己的操作。
八、Redis主从复制机制
1.读写分离的好处:
- 性能优化:主服务器专注于写操作,可以用更适合写入数据的模式工作;同样,从服务器专注于读操作,可以用更适合读取数据的模式工作。
- 强化数据安全,避免单点故障:由于数据同步机制的存在,各个服务器之间数据保持一致,所以其中某个服务器宕机不会导致数据丢失或无法访问。从这个角度说参与主从复制的Redis服务器构成了一个集群。
2.搭建步骤
①思路
Redis集群在运行时使用的是同一个可执行文件,只是对应的配置文件不同。
每个配置文件中相同的参数是:
1 | daemonize yes |
不同的参数有:
配置项名称 | 作用 | 取值 |
---|---|---|
port | Redis服务器启动后监听的端口号 | 6000 7000 8000 |
dbfilename | RDB文件存储位置 | dump6000.rdb dump7000.rdb dump8000.rdb |
logfile | 日志文件位置 | /usr/local/cluster-redis/logs/redis6000.log /usr/local/cluster-redis/logs/redis7000.log /usr/local/cluster-redis/logs/redis8000.log |
pidfile | pid文件位置 | /var/run/redis6000.pid /var/run/redis7000.pid /var/run/redis8000.pid |
②步骤
- 第一步:创建/usr/local/cluster-redis目录
- 第二步:把原始未经修改的redis.conf复制到/usr/local/cluster-redis目录
- 第三步:把/usr/local/cluster-redis目录下的redis.conf复制为redis6000.conf
- 第四步:按照既定计划修改redis6000.conf中的相关配置项
- daemonize yes
- dir
- port
- dbfilename
- logfile
- pidfile
- 第五步:复制redis6000.conf为redis7000.conf
- 第六步:修改redis7000.conf中的相关配置项
- port
- dbfilename
- logfile
- pidfile
- 第七步:复制redis6000.conf为redis8000.conf
- 第八步:修改redis8000.conf中的相关配置项
- port
- dbfilename
- logfile
- pidfile
③启动Redis主从复制集群
1 | /usr/local/redis/bin/redis-server /usr/local/cluster-redis/redis6000.conf |
使用redis-cli停止指定服务器的命令格式如下:/usr/local/bin/redis-cli -h IP地址 -p 端口号 shutdown
3.主从关系
①查看主从关系
1 | 127.0.0.1:6000> info replication |
刚刚启动的集群服务器中每一个节点服务器都认为自己是主服务器。需要建立主从关系。
②设定主从关系
在从机上指定主机位置即可
1 | SLAVEOF 127.0.0.1 6000 |
③取消主从关系
在从机上执行命令
1 | SLAVEOF NO ONE |
4.初步测试
测试1:在主机写入数据,在从机查看
测试2:在从机写入数据报错。配置文件中的依据是:slave-read-only yes
测试3:主机执行SHUTDOWN看从机状态
从机依旧是slave状态,显示主机下线,可以查询数据
测试4:主机恢复启动,看从机状态
显示主机上线,可以查询数据
测试5:从机SHUTDOWN,此时主机写入数据,从机恢复启动查看状态。重新设定主从关系后看新写入的数据是否同步。
从机重新启动又变成master状态,需要重新建立主从关系才可以同步主机新写的数据。
5.哨兵模式
①作用
通过哨兵服务器监控master/slave实现主从复制集群的自动管理。
②相关概念
[1]主观下线
1台哨兵检测到某节点服务器下线。
[2]客观下线
认为某个节点服务器下线的哨兵服务器达到指定数量。这个数量后面在哨兵的启动配置文件中指定。
③配置方式
简单起见我们只配置一台哨兵。我们所需要做的就是创建一个哨兵服务器运行所需要的配置文件。
新建并编辑sentinel的配置文件
1 | vim /usr/local/cluster-redis/sentinel.conf |
格式 | sentinel monitor 为主机命名 主机IP 主机端口号 将主机判定为下线时需要Sentinel同意的数量 |
---|---|
例子 | sentinel monitor mymaster 127.0.0.1 6000 1 |
④启动哨兵
根据新建的sentinel的配置文件启动redis
1 | /usr/local/redis/bin/redis-server /usr/local/cluster-redis/sentinel.conf --sentinel |
下面是哨兵模式的日志打印情况
1 | 启动哨兵模式,根据配置指定主服务器,并自动建立主从关系 |
九、发布订阅
1.订阅一个频道
1 | 127.0.0.1:6379> SUBSCRIBE cctv1 |
2.在一个频道上发布信息
1 | 127.0.0.1:6379> PUBLISH cctv1 weather |
1 | 127.0.0.1:6379> SUBSCRIBE cctv1 |
十、Jedis
代码示例:Github-JedisDemo
1.一个对比
MySQL | Redis | |
---|---|---|
连接 | Connection | Jedis |
连接池 | C3P0等等 | JedisPool |
操作完成 | 关闭连接 | 关闭连接 |
2.Redis准备
①理解Redis配置文件中bind配置项含义
bind后面跟的ip地址是客户端访问Redis时使用的IP地址。看下面例子:
| bind值 | 访问方式 |
| ————— | —————————— |
| 127.0.0.1 | ./redis-cli -h 127.0.0.1 |
| 192.168.200.100 | ./redis-cli -h 192.168.200.100 |
②查看Linux系统本机IP
远程客户端访问Linux服务器时不能使用127.0.0.1,要使用网络上的实际IP。可以用ifconfig命令查看。
③将Redis配置文件中的bind配置项设置为本机IP。
1 | bind [你的实际IP] |
3.Jedis
1 | <dependency> |
1 | //指定Redis服务器的IP地址和端口号 |
4.JedisPool
1 | //声明Linux服务器IP地址 |
代码示例:Github-JedisDemo