0.内容
- NoSQL概述
- Redis概述、使用场景
- 单机版Redis安装(Windows、CentOS7)
- Redis多数据库特点
- Redis常用全局命令
- Redis常用数据类型
- 使用Jedis、spring-data-redis、Spring Boot连接单机版Redis
- 简单的点赞接口开发
- Redis持久化方式
- Redis事务
- Redis集群模式
- 主从模式
- 哨兵模式
- 分片集群模式(在CentOS7上安装)
- 使用Jedis、spring-data-redis、Spring Boot连接集群Redis
- 简单排行榜接口开发
- Redis持久化
- Redis事务
- Redis集群模式
- Jedis连接Redis集群
- Spring Data Redis连接Redis集群
- Spring Boot连接Redis集群
- 简单排行榜练习
- Redis官网:https://redis.io
- Redis中文网:http://www.redis.cn
- Redis所属公司:Pivotal(Spring所在的公司)
- Redis源码地址:https://github.com/antirez/redis
1. NoSQL - Not Only SQL
**MySQL**、**Oracle**、**DB2**:关系型数据库
`结构化数据`:使用关系型数据库表示和存储,表现形式就是二维行列结构;
**NoSQL**:存储非结构化和半结构化数据
`非结构化数据`:没有固定存储结构,文件、图片、音视频等
`半结构化数据`:可以认为是结构化数据的一种,只不过不是以二维行列形式存储,但是数据包含相关标记,比如JSON、XML;
1.1 NoSQL数据库类型
- 键值对数据库(Key-Value数据库)
代表数据库:Redis、Memcached - 列式数据库
代表数据库:谷歌的BigTable、Apache的HBase - 文档数据库
这种数据库存储半结构化数据:一般存储为json格式,这种数据库更接近关系型数据库;
代表数据库:MongoDB
、ElasticSearch(ES)
- 图数据库
并不是存储图片,而是存储数据间关系;
适合做社交网络、关系图谱;
代表数据库:Neo4J
、OrientDB
2. Redis概述
- Redis是一个
键值对类型
的内存数据库; - Redis支持字符串、哈希、列表、集合、有序集合等数据结构;
- Redis具有内置的数据复制、回收、事务和不同级别的磁盘上的持久性;
- Redis是纯内存操作,具备很高的读写性能;读的速度能达到110000次/s,写的速度能达到81000次/s;
- Redis支持主从模式的数据备份,数据可扩展性高;
- Redis支持集群(Redis3.0 +);
2.1 Redis的使用场景
- 缓存:缓存一些常用数据、缓存Session会话等
- 排行榜
- 简单的消息队列
- 好友关系:点赞、好友推荐等
- ......
3. Redis单机版安装
Redis官方只提供了Linux的安装版本,不提供windows的安装版本,但是微软使用Redis源码编译了一个windows的版的Redis安装包;
Window64位下载地址:[https://github.com/MicrosoftArchive/redis/releases](https://github.com/MicrosoftArchive/redis/releases)
3.1 Windows安装Redis
- 解压redis安装文件
- 启动redis服务,双击
redis-server.exe
即可 - 命令行方式启动redis服务
- 启动redis客户端
双击redis-cli.exe
3.2 Centos7安装单机版Redis5.0.4
- 安装gcc-c++
yum install -y gcc-c++
- 上传安装包
redis-5.0.4.tar.gz
到/opt
目录 - 解压
redis-5.0.4.tar.gz
到/opt
目录
tar -zxf redis-5.0.4.tar.gz [-C /opt]
- 编译安装Redis
[root@localhost opt]# mv redis-5.0.4 redis
[root@localhost opt]# cd redis
[root@localhost redis]# make
[root@localhost redis]# cd src
[root@localhost src]# make install
- 修改配置文件(
/opt/redis/redis.conf
) - bind 127.0.0.1 注释这一行(69行)
- protected-mode no (将保护模式修改为no)(88行)
- daemonize yes (设置为守护进程,把no改为yes)(136行)
- 启动redis server
cd /opt/redis
redis-server redis.conf
- 启动redis-cli客户端
redis-cli [-h 127.0.0.1 -p 6379 -a 密码]
-h:host,连接主机,默认连接127.0.0.1
-p:port,redis服务器端口号,默认连接端口是6379
-a:auth,redis登录密码
- 停止redis服务端
redis-cli shutdown
4. Redis的多数据库特点
- Redis默认支持
16个数据库
,下标从0开始(0-15) - 可以通过redis.conf中的
databases
配置
4.1 Redis多数据库缺点
- 不支持自定义数据库名称。
- 不支持为每个数据库设置访问密码。
- 多个数据库之间不是完全隔离的,FLUSHALL命令会清空所有数据库的数据。
- 多数据库不适用于存储不同应用的数据。
- Redis集群不支持多数据库。
5. Redis常用的全局命令
keys *
:查看所有的键,支持通配符查询,如:keys name*
exists key
:测试是否存在指定的key,存在返回1,不存在返回0ttl key
:查看key的剩余有效时间,-1
代表永不过期,-2
表示key已经过期- expire key seconds:设置key的过期时间,单位是秒
del key
:删除某个keyrename key newkey
:修改key的名称flushall
:清空所有数据(会跨库清空数据)info [section]
:查看数据信息,info Server,info CPU、info Replicationpersist key
:取消key的过期时间- kill 关闭进程
- sed -i 's/6001/6002/g' redis.conf 将配置文件redis.conf中的6001全部替换为 6002
6. Redis的常用数据类型
6.1 string类型
string类型是redis中最基本的类型,并且是二进制的安全的,可以存储序列化的对象、二进制图片、一个简单的字符串、数值等。string类型的键允许存储的数据最大容量是512MB。
特别注意:mset
、mget
在集群环境下无法使用;
6.2 hash类型
hash是一个string类型的field和value的映射表。特别适合存储对象,将一个对象存储在hash类型中会占用更少的内存,而且可以方便的操作对象。
6.3 list类型
list是一个链表结构,类似JDK的LinkedList、Queue,list类型的每个子元素都是string类型的双向链表;
6.4 set类型
set是string类型的无序不可重复的集合。Set是通过hash table实现的,添加、删除和查找的复杂度都是O(1),可以对set取并集、交集、差集
,通过set的这些操作我们可以实现好友推荐功能。
6.5 zset类型
zset有序集合,类似SortedSet。
7. 使用Jedis连接单机版Redis服务器
- Jedis源码地址:https://github.com/redis/jedis
- Maven依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
- 使用Jedis的连接池
JedisPoolConfig:最大连接数
8. Spring整合Jedis连接单机版Redis
9. Spring-Data-Redis整合Jedis连接单机版Redis
10. Spring Boot使用Redis
- Spring Boot Redis Starter默认整合了Lettuce框架
- 简单点赞接口 详细见工程redis-boot
- 点赞、取消点赞
- 查看点赞数量
- 查看点赞人
11.Redis的持久化策略
Redis提供了两种持久化策略:`RDB` 和 `AOF`
11.1 RDB持久化 - 默认
- 快照文件名称设置
通过redis.conf
中的dbfilename
设置
默认值:dbfilename "dump.rdb"
- 快照文件存放位置
通过redis.conf
中的dir
设置
默认值:dir ./
表示在执行redis-server命令的目录下生成文件 - 快照(RDB持久化)策略配置
save 900 1 900秒内有一个修改就执行持久化
save 300 10 300秒内有10个修改就执行持久化
save 60 10000 60秒内有一万个修改就执行持久化
增加5秒内有一个可以被修改就触发RDB持久化
save 5 1
2199:M 06 Sep 2021 09:45:38.783 * 1 changes in 5 seconds. Saving...
2199:M 06 Sep 2021 09:45:38.784 * Background saving started by pid 2228
**2228:C 06 Sep 2021 09:45:38.786 _ DB saved on disk_
**2228:C 06 Sep 2021 09:45:38.788 _ RDB: 4 MB of memory used by copy-on-write_
2199:M 06 Sep 2021 09:45:38.891 * Background saving terminated with success
11.1.1 RDB持久化过程
RDB持久化是Redis定期将内存中的`数据集快照`写入磁盘,实际操作过程是主进程创建一个子进程,先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储,整个过程`主进程`不进行任何IO操作,保证Redis的高效性。
11.1.2 RDB持久化的触发方式
自动触发
和手动触发
- 自动触发(默认配置):从redis.conf中配置
- 手动触发
- save
执行此命令会阻塞Redis服务器,执行命令期间,Redis不能处理其它命令,直到RDB过程完成为止。
执行日志如下
2199:M 06 Sep 2021 09:50:13.544 * DB saved on disk
- bgsave
执行该命令时,Redis会在后台异步进行快照操作,做快照的同时还可以响应客户端请求;此时Redis主进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。
执行日志如下:
2199:M 06 Sep 2021 09:49:30.471 * Background saving started by pid 2235
**2235:C 06 Sep 2021 09:49:30.474 _ DB saved on disk_
**2235:C 06 Sep 2021 09:49:30.476 _ RDB: 4 MB of memory used by copy-on-write_
2199:M 06 Sep 2021 09:49:30.481 * Background saving terminated with success
11.2 AOF持久化
AOF持久化以`日志的形式`记录服务器所处理的每一个写操作和删除操作,以文本的方式记录,可以打开文件看到详细的操作记录。
- aof文件名称设置
使用redis.conf
中的appendfilename
设置
默认设置:appendfilename "appendonly.aof"
- 如何开启aof持久化
使用redis.conf
中的appendonly yes
设置
默认设置:appendonly no
表示不开启aof持久化 - aof文件存放位置
过redis.conf
中的dir
设置
默认值:dir ./
表示在执行redis-server命令的目录下生成文件
11.2.1 Redis支持三种同步AOF文件的策略
通过redis.conf中的`appendfsync设置`
no
: 不进行同步,依靠操作系统来进行同步. Faster.always
: always表示每次有写操作都进行同步. Slow, Safest.everysec
: 表示对写操作进行累积,每秒同步一次. Compromise.
默认是"everysec",按照速度和安全折中这是最好的。
12.Redis的事务
Redis对事务的支持比较简单,它是一组命令的集合,命令被顺序的执行;Redis也可以放弃事务的执行,此时所有事务里面的命令都不会执行。
Redis只能保证一个client发起的事务中的命令可以连续的执行,中间不会插入其他client的命令,因为Redis是单线程架构,所以在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的。
Redis的事务`没有隔离级别`的概念,因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这种问题了。
Redis的事务`不保证原子性`,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力。
`Redis集群不支持事务操作`;
12.1 Redis事务的相关命令
multi
:开启事务exec
:执行事务discard
:取消事务watch
:监控键值unwatch
:取消监控
12.2 Redis事务的基本过程
- 发送一个事务的命令
multi
给redis; - 依次把要执行的命令发送给Redis,Redis接到这些命令,并不会立即执行,而是放到等待执行的事务队列里面;
- 发送执行事务的命令
exec
给Redis; - Redis会保证一个事务内的命令依次执行,而不会被其它命令插入;
12.3 Redis事务过程中的错误处理
Redis的事务非常简单,当然会存在一些问题。
Redis只能保证事务的每个命令连续执行,但是如果事务中的一个命令失败了,并不回滚其他命令,下面举例看错误处理;
- 如果是某个命令执行错误(使用方式错了),那么其它的命令仍然会正常执行,然后在执行后返回错误信息;
- 如果任何一个命令的语法有错,redis会直接返回错误,所有的命令都不会执行
注意
: Redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态;
12.4 Redis事务扩展 - 乐观锁
Redis使用`watch`来提供乐观锁定;
当`exec`被调用后,所有的之前被监视的键会被取消监视,不管事务是否被取消或执行。并且当客户端连接丢失的时候,所有键都会被取消监视。
12.4.1 乐观锁介绍
乐观锁大多是基于`数据版本(version)`的记录机制实现的。
什么是数据版本?
数据版本就是为数据增加一个版本标识version,更新数据时,对此版本号加 1,当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值大于当前数据库中的version值时才更新,否则更新失败。
12.4.2 乐观锁举例
小明的账户有余额1000;
- 操作员A将小明的信息读出(此时 version=1),并准备从其帐户余额中扣除100(1000-100); 剩余900
- 在操作员A操作的过程中,操作员B也读入小明的信息(此时 version=1),并准备从其帐户余额中扣除500(1000-500); 剩余500
- A完成了修改工作后,将数据版本号加 1(此时 version=2),帐户扣除后余额为900,提交至数据库更新,此时由于提交数据版本大于数据库记录当前版本(2 > 1),数据被更新,数据库记录 version 更新为 2;
- 在A完成更新操作之后,B也完成了操作,她也将版本号加 1(version=2)并试图向数据库提交数据(此时小明的余额为500),但比对数据库记录版本时发现,B提交的数据版本号为 2,数据库记录当前版本也为 2,不满足提交版本必须大于记录当前版本才能执行更新的乐观锁策略,因此,B的提交被驳回;
12.4.3 Redis的乐观锁测试
- 设置balance为1000,并使用watch监控balance
- 第一个客户端开启事务,并将balance修改为900,但是没有执行事务
- 第二个客户端直接把balance修改为500
- 第一个客户端再次执行exec,结果没有修改成功
13. Redis集群模式
Redis集群模式:`主从模式`、`哨兵模式`、`分片集群模式`
13.1 Redis的主从模式
Redis的主从模式,使用异步复制,从节点异步从主节点复制数据,主节点提供读写服务,从节点只提供读服务(这个是默认配置,可以通过修改配置文件`replica-read-only`控制)。
主节点可以有多个从节点。
配置一个从节点只需要在redis.conf文件中指定:
replicaof master-ip master-port
13.1.1 主从复制配置
一主一从、一主多从、一主一从一从...
13.1.2 主从复制基本过程
- Slave启动时,向Master发送sync命令,以实现全量复制。
- Mater(主库)接到sync请求,会在后台保存快照(也就是进行RDB持久化),
并将快照期间接收到命令缓存起来
。 - 快照完成后,Master(主库)会将快照文件和所有的缓存的命令发送给Slave(从库)。
- Slave(从库)接收后,会载入快照文件并执行缓存的命令,从而完成复制的初始化。
- 在数据库使用阶段,Master(主库)会自动把每次收到的写命令同步到从服务器。
13.1.3 Redis乐观复制策略
Redis采用乐观复制的策略,允许一定时间内主从数据库的内容不同,当然最终的数据会相同。此策略保证了Redis性能,在进行复制时,Master(主库)并不阻塞,继续处理client的请求。
但是Redis同样提供了配置用来限制**只有当数据至少同步给指定数量的Slave(从库)时**,Master(主库)才可写,否则返回错误。配置是:`min-replicas-to-write`、`min-replicas-max-lag`。
13.1.4 主从模式配置
- 主节点配置
bind 127.0.0.1 # 注释掉
protected-mode no # 关闭保护模式(将yes改为no)
daemonize yes # 守护进程模式开启(将no改为yes)
logfile "/opt/redis/redis.log"
- 从节点配置
bind 127.0.0.1 # 注释掉
protected-mode no # 关闭保护模式
daemonize yes # 守护进程模式开启
replicaof 主节点ip 主节点端口号 # replicaof 192.168.1.128 6379
13.2 Redis哨兵模式
- 主从方式有个问题,就是
Master(主库)
挂了之后,无法重新选举新的节点作为主节点进行写操作,导致服务不可用。 - Redis提供了
哨兵工具
来实现监控Redis系统的运行情况,能够实现如下功能:
1、监控主从数据库运行是否正常。
2、当主数据库出现故障时,自动将从数据库转换为主数据库。
13.2.1 哨兵配置
- 配置
/opt/redis/sentinel.conf文件
daemonize yes # 改为yes
logfile /opt/redis/sentinel.log
sentinel monitor mymaster 192.168.85.128 6379 1
sentinel down-after-milliseconds mymaster 5000 # 改为5s,默认30s
- 启动哨兵:
redis-sentinel /opt/redis/sentinel.conf
- 进入哨兵:
redis-cli -h 192.168.1.128 -p 26379
- 查看哨兵信息:
redis-cli -h 192.168.1.128 -p 26379 info Sentinel
13.3 分片集群模式
目前比较流行的Redis集群方案
系统 | 贡献者 | 编程语言 |
---|---|---|
Twemproxy | C | |
Redis Cluster | Redis官方 | C |
Codis | 豌豆荚 | Go、C |
- Redis集群是一个提供在多个Redis节点间共享数据的程序集。
- Redis集群并
不支持处理多个key的命令(比如mset、mget等)
,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误。 - Redis集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令。
13.3.1 Redis 集群的优势
- 自动分割数据到不同的节点上。
- 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
13.3.2 Redis 集群的数据分片
Redis集群引入了**哈希槽**的概念。
Redis 集群有`16384个哈希槽`,每个key通过`CRC16校验`后对16384取模来决定放置哪个槽。集群的每个节点负责一部分hash槽。
举个例子:比如当前集群有3个主节点,那么:
- 节点A包含 0 到 5500号哈希槽。
- 节点 B 包含5501 到 11000 号哈希槽。
- 节点 C 包含11001 到 16383号哈希槽。
这种结构很容易添加或者删除节点:比如我们想新添加个节点D, 我们需要将节点 A、B、 C中的部分槽移动到D上。如果我想移除节点A,需要将A中的槽移到B和C节点上。然后将没有任何槽的A节点从集群中移除即可。由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态。
13.3.3 Redis集群安装
安装方式:在一台机器上安装6个节点(3主3从)
安装节点数:必须有3个或3个以上的主节点,所以采用3主3从方式安装;
安装步骤
- 在/opt目录下创建
cluster
目录 - 在/opt/cluster下创建6个目录,分别是6001、6002...6006
- 拷贝一个新的redis.conf文件到/opt/redis-cluster/6001目录下
- 修改redis.conf
1. bind 本机的ip地址 # 绑定ip(69行)
2. protected-mode no # 关闭保护模式(88行)
3. port 600* # 端口号为6001 - 6006(92行)
4. daemoinze yes # 开启守护进程模式(136行)
5. pidfile "/var/run/redis_600*.pid" (158行)
6. logfile /opt/cluster/600*/redis.log (171行)
7. dir /opt/cluster/600* # 持久化文件的默认保存位置、集群配置文件(263行)
8. cluster-enabled yes # 启动集群模式(去掉注释 838行)
9. cluster-config-file nodes-600*.conf # 集群自动生成的文件,自动写到dir目录
- 按顺序启动每一个节点
redis-server /opt/cluster/6001/redis.conf
redis-server /opt/cluster/6002/redis.conf
redis-server /opt/cluster/6003/redis.conf
redis-server /opt/cluster/6004/redis.conf
redis-server /opt/cluster/6005/redis.conf
redis-server /opt/cluster/6006/redis.conf
- 使用
redis-cli
命令创建集群
redis-cli --cluster create 192.168.1.128:6006 192.168.1.128:6001 192.168.1.128:6002 192.168.1.128:6003 192.168.1.128:6004 192.168.1.128:6005 --cluster-replicas 1
注意:这个创建集群的命令只需要执行一次,下次启动时,只需要执行第五步
的命令即可 - 登录集群
redis-cli -c -h 192.168.1.128 -p 6001
-c
: 以集群的方式连接redis
-h
: 连接的主机(host)
-p
: 端口号(port)
计算key的hash槽的槽号:cluster keyslot key的名称
14. Jedis连接Redis集群
15. Spring Data Redis连接Redis集群
- 单机版
RedisStandaloneConfiguration
RedisConnectionFactory - JedisConnectionFactory
StringRedisTemplate - 集群版
JedisPoolConfig
Iterable<RedisNode>
RedisClusterConfiguration
RedisConnectionFactory - JedisConnectionFactory
StringRedisTemplate
16. 整合Spring Boot实现简单的排行榜
- 随机英雄添加武力值(score:0-1000)
- 显示所有英雄的武力值排行
- 显示top3(前三名)
- 显示武力值在500-1000之间的英雄
zadd
zrevrange key 0 2 withscores
zrevrangebyscore key 1000 500 withscores