¶一、简介
Redis
是key-value
(键值对)的存储系统。支持存储的value
类型相对更多,包括string
、list
、set
(集合)、zset
(有序集合)和hash
(哈希类型),算一种nosql内存型缓存数据库。
NoSQL
,指的是非关系型的数据库。NoSQL
有时也称作Not Only SQL
的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。NoSQL
一般应用于超大规模数据的存储。关系型数据库已经不适合处理当今成倍数据量增加的大型互联网商务应用了。这时nosql
数据库由于其更高的性能、更快的速度、更好的可扩展性等优势对解决大规模数据起到了良好的应用作用。
NoSQL四大分类
分类 | Examples举例 | 典型应用场景 | 数据模型 | 优点 | 缺点 |
---|---|---|---|---|---|
键值(key-value) | Redis,Tokyo Cabinet/Tyrant, Voldemort, Oracle BDB | 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等。 | Key 指向 Value 的键值对,通常用hash table来实现 | 查找速度快 | 数据无结构化,通常只被当作字符串或者二进制数据 |
列存储数据库 | Cassandra, HBase, Riak | 分布式的文件系统 | 以列簇式存储,将同一列数据存在一起 | 查找速度快,可扩展性强,更容易进行分布式扩展 | 功能相对局限 |
文档型数据库 | CouchDB, MongoDb | Web应用(与Key-Value类似,Value是结构化的,不同的是数据库能够了解Value的内容) | Key-Value对应的键值对,Value为结构化数据 | 数据结构要求不严格,表结构可变,不需要像关系型数据库一样需要预先定义表结构 | 查询性能不高,而且缺乏统一的查询语法。 |
图形(Graph)数据库 | Neo4J, InfoGrid, Infinite Graph | 社交网络,推荐系统等。专注于构建关系图谱 | 图结构 | 利用图结构相关算法。比如最短路径寻址,N度关系查找等 | 很多时候需要对整个图做计算才能得出需要的信息,而且这种结构不太好做分布式的集群方案。 |
NoSQL适用场景:1、数据模型比较简单;2、需要灵活性更强的IT系统;3、对数据库性能要求较高;4、不需要高度的数据一致性;5、对于给定key,比较容易映射复杂值的环境。
通俗来说,Oracle
、mysql
、sqlserver
等这样的关系型数据库主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。而redis
主要将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但相应的保存时间有限。
使用Redis
的情景一般是会话缓存(session cache
),用Redis
缓存会话比其他存储(如Memcached
)的优势在于:Redis
提供持久化,即可以将内存中的数据序列化到硬盘中,如此以确保用户数据的安全性。此外Redis
哎集群方面具有很好的优势。
NoSQL优缺点
优点
数据高并发读写
海量数据存储和访问效率高
对数据可扩展且高可用
缺点
ACID相比于关系型数据库过于简单
无法做太复杂的关系数据库模型
¶二、常用命令大全
¶1. key相关
1 | $ keys * #查询当前库的所有键 |
案例
(1)查询当前库的所有键
1 | 127.0.0.1:6379> keys * |
(2)修改 key的名称
1 | 127.0.0.1:6379> set name qcmoke |
¶2. String相关
1 | $ set key value #添加键值对 |
案例
(1)添加键值对
set key value
1 | 127.0.0.1:6379> set name zhangsan |
如果已经存在相应的key/value
,那么会将原本的值覆盖掉。添加完成后,会根据配置文件中的dir
的路径每隔一段时间序列化生成dump.rdb
文件。这个文件可以备份和删除,但删除了相应的数据库中就没有相应的数据了,故不要轻易的删除,这很危险。
setnx key value
如果不存在key则设置,如果存在key则不设置
1 | 127.0.0.1:6379> setnx name qcmoke |
(2)查询对应键值
get key
1 | 127.0.0.1:6379> get name |
(3)删除已存在的键
del key
1 | 127.0.0.1:6379> del name |
¶3. 哈希(Hash)
1 | $ HDEL key field1 [field2] #删除一个或多个哈希表字段 |
案例
(1)将哈希表 key 中的字段 field 的值设为 value
1 | 127.0.0.1:6379> hmset user age 21 |
(2)将多个 field-value (域-值)对设置到哈希表 key 中
1 | 127.0.0.1:6379> hmset user name zhangsan description "a good boy" |
(3)从hash里获取指定字段的值
1 | 127.0.0.1:6379> hget user name |
(4)从hash获取指定 key 的所有字段和值
1 | 127.0.0.1:6379> hgetall user |
(5)从hash获取指定 key 的所有值
1 | 127.0.0.1:6379> hvals user |
¶4. 列表(List)
根据收尾添加的不同,既可以实现栈,也可以实现队列。
1 | $ BLPOP key1 [key2 ] timeout # 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
案例
(1)将一个或多个值插入到列表头部
1 | 127.0.0.1:6379> lpush lkey zhangsan |
(2)获取列表指定范围内的元素
1 | 127.0.0.1:6379> LRANGE lkey 0 10 |
¶5. 集合Set
1 | $ SADD key member1 [member2] #向集合添加一个或多个成员 |
案例
(1)向集合添加一个或多个成员
1 | 127.0.0.1:6379> sadd skey zhangsan |
(2)返回集合中的所有成员
1 | 127.0.0.1:6379> smembers skey |
¶6. 有序集合(sorted set)
1 | $ ZADD key score1 member1 [score2 member2] #向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
案例
(1)向有序集合添加一个或多个成员,或者更新已存在成员的分数
1 | 127.0.0.1:6379> zadd sskey 1 zhangsan |
(2)过索引区间返回有序集合成指定区间内的成员
1 | 127.0.0.1:6379> zrange sskey 0 10 |
(3)取分数和值
1 | 127.0.0.1:6379> zrange sskey 0 10 WITHSCORES |
¶7. 高级命令
1 | $ select [数据库下标] #选择数据库,数据库为0--15(16个),默认进入第0个 |
案例
(1)切换到下标为某个数字的数据库
1 | 127.0.0.1:6379> select 1 |
(2)清空当前数据库的key
1 | 127.0.0.1:6379> flushdb |
关键字可大小写
更多命令请参考:https://redis.io/commands
¶三、部署方案
为了实现Redis的高并发高可用应用,Redis支持单机、主从、哨兵、集群多种架构模式部署方案。
¶单机模式
¶概念
单机模式顾名思义就是安装一个 Redis,启动起来,业务调用即可。例如一些简单的应用,并非必须保证高可用的情况下可以使用该模式。
¶优缺点
优点
- 部署简单;
- 成本低,无备用节点;
- 高性能,单机不需要同步数据,数据天然一致性。
缺点
- 可靠性保证不是很好,单节点有宕机的风险。
- 单机高性能受限于 CPU 的处理能力,Redis 是单线程的。
单机 Redis 能够承载的 QPS(每秒查询速率)大概在几万左右。取决于业务操作的复杂性,Lua 脚本复杂性就极高。假如是简单的 key value 查询那性能就会很高。假设上千万、上亿用户同时访问 Redis,QPS 达到 10 万+。这些请求过来,单机 Redis 直接就挂了。系统的瓶颈就出现在 Redis 单机问题上,此时我们可以通过主从复制解决该问题,实现系统的高并发。
¶安装部署
¶1. window版安装
步骤大致如下:
(1)下载
下载地址:https://github.com/microsoftarchive/redis/releases
(2)启动和关闭
解压到任意目录后,点击安装目录里的redis-server.exe即可启动,关闭redis-server.exe启动的窗口即可关闭。
(3)开启后台守护进程
cmd进入安装目录并执行以下命令即可安装成系统守护进程服务。(当然你可以将安装目录放到环境变量中,就可以在任意目录执行redis命令了,这里为了简便就不做此操作了)
1 | redis-server --service-install redis.windows-service.conf --loglevel verbose |
(4)启动和关闭守护进程服务
1 | #启动(如果启动失败,在安装目录里创建一个名称为Logs的文件夹即可) |
(4)卸载
-
如果没有开启守护进程服务,那么直接删除安装目录即可卸载。
-
如果开启守护进程服务,那么可在安装目录里通过执行以下命令来卸载守护进程服务,执行该命令后删除安装目录即可完全卸载。
1 | redis-server --service-uninstall |
更多内容可参考菜鸟教程。
¶2. Linux版安装
这里主要讲linux
下编译安装。
(1)下载
下载地址: https://redis.io/download ,这里使用的是3.0版本。
1 | #下载redis-3.0.0 |
(2)安装
1 | #解压到/usr/local/ |
看到类似“Hint: It's a good idea to run 'make test' ;)
”这样的提示表示编译完成。make 后编译好的文件会保存到src目录下。这些文件中有两个重要的文件:
redis-server 服务端程序
redis-cli 客户端程序
其实这个时候我们已经可以执行redis-server
和redis-cli
直接使用了,但为了更好的管理程序,我们可以将这些编译好的文件和配置文件移动到其他目录去。如/usr/local/redis/bin/
和/usr/local/redis/etc/
。
1 | #创建两个目录用来存放redis配置文件和编译好的文件 |
(3)卸载
直接删除/usr/local/redis-3.0.0
、/usr/local/redis/bin/
和/usr/local/redis/etc/
目录即可完成卸载。
(4)启动服务端
1 | #redis-server + redis配置文件 一起启动服务 |
可以通过打开另一个终端执行ps -ef | grep redis
或者 ps -ef | grep 6379
查看redis
线程。
可以按Ctrl+C
中断停止服务端启动。
(5)配置服务端
默认开启redis-server
需要保持当前终端开启才能使用,如果关闭当前终端或者中断进程了那么服务就关闭了,如果希望后台启守护进程,我们可以修改redis
的配置文件,修改daemonize
的值为yes
来实现。
1 | $ vim /usr/local/redis/etc/redis.conf |
注意重启redis-server后才能生效
以下是其他配置,但学习的话并不建议
1 | port 6379 #默认端口,可以修改 |
(6)启动服务端守护进程
1 | $ /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf |
(7)关闭服务端守护进程
1 | $ /usr/local/redis/bin/redis-cli shutdown |
(8)客户端使用
1)启动客户端
1 | $ /usr/local/redis/bin/redis-cli |
2)关闭客户端
按Ctrl+C
就能停止客户端启动
¶3. docker版安装
可参考:https://www.qcmoke.site/devops/docker.html#5-安装redis
¶主从复制
¶概念
Redis 的复制(Replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(Master),而通过复制创建出来的复制品则为从服务器(Slave)。 只要主从服务器之间的网络连接正常,主服务器就会将写入自己的数据同步更新给从服务器,从而保证主从服务器的数据相同。
数据的复制是单向的,只能由主节点到从节点,简单理解就是从节点只支持读操作,不允许写操作。主要是读高并发的场景下用主从架构。主从模式需要考虑的问题是:当 Master 节点宕机,需要选举产生一个新的 Master 节点,从而保证服务的高可用性。
¶优缺点
优点
- Master/Slave 角色方便水平扩展,QPS 增加,增加 Slave 即可;
- 降低 Master 读压力,转交给 Slave 节点;
- 主节点宕机,从节点作为主节点的备份可以随时顶上继续提供服务;
缺点
- 可靠性保证不是很好,主节点故障便无法提供写入服务;
- 没有解决主节点写的压力;
- 数据冗余(为了高并发、高可用和高性能,一般是允许有冗余存在的);
- 一旦主节点宕机,从节点晋升成主节点,需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预;
- 主节点的写能力受到单机的限制;
- 主节点的存储能力受到单机的限制。
¶安装部署
这里部署节点架构为:1主2从。
因为这里只是学习使用所以就都搭建在同一台服务器上了(即所谓为集群),如果要在生产上使用则应该每个redis节点都应该是一台服务器。为了简化部署过程,这里通过使用redis配置模板文件和docker compose来简化搭建过程。
¶redis配置
创建配置模板文件
1 | mkdir -p /opt/redis/conf |
通过模板文件动态生成所有节点的配置文件
1 | #主从节点的密码 |
¶docker配置
1 | mkdir -p /opt/redis |
1 | version: '3' |
1 | #创建并启动所有服务容器 |
¶哨兵模式
¶概念
主从模式中,当主节点宕机之后,从节点是可以作为主节点顶上来继续提供服务,但是需要修改应用方的主节点地址,还需要命令所有从节点去复制新的主节点,整个过程需要人工干预。
于是,在 Redis 2.8 版本开始,引入了哨兵(Sentinel)这个概念,在主从复制的基础上,哨兵实现了自动化故障恢复。如上图所示,哨兵模式由两部分组成,哨兵节点和数据节点:
- 哨兵节点:哨兵节点是特殊的 Redis 节点,不存储数据;
- 数据节点:主节点和从节点都是数据节点。
Redis Sentinel 是分布式系统中监控 Redis 主从服务器,并提供主服务器下线时自动故障转移功能的模式。其中三个特性为:
- 监控(Monitoring):Sentinel 会不断地检查你的主服务器和从服务器是否运作正常;
- 提醒(Notification):当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知;
- 自动故障迁移(Automatic failover):当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。
¶优缺点
优点
- 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都有;
- 主从可以自动切换,系统更健壮,可用性更高;
- Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
缺点
- 主从切换需要时间,会丢失数据;
- 还是没有解决主节点写的压力;
- 主节点的写能力,存储能力受到单机的限制;
- 动态扩容困难复杂,对于集群,容量达到上限时在线扩容会变得很复杂。
¶安装部署
这里部署节点架构为:1主2从3哨兵。
因为这里只是学习使用所以就都搭建在同一台服务器上了(即所谓为集群),如果要在生产上使用则应该每个redis节点都应该是一台服务器。为了简化部署过程,这里通过使用redis配置模板文件和docker compose来简化搭建过程。
¶redis配置
创建配置模板文件
1 | mkdir -p /opt/redis/conf |
通过模板文件动态生成所有节点的配置文件
1 | #主从节点的密码 |
¶docker配置
1 | mkdir -p /opt/redis |
1 | version: '3' |
1 | #创建并启动所有服务容器 |
¶参考
¶集群模式
¶概念
1、主从复制模式只要解决了单机节点查询并发量瓶颈。但主节点出故障需要人为替换从节点顶替主节点。即主从复制模式解决了读并发,但为解决写并发,同时没有高可用性。
2、哨兵模式在主从复制模式的基础上实现了自动化故障恢复。即在主从复制模式的基础上解决了高可用性,但仍然未解决写并发。
3、为了解决哨兵模式的写并发问题,诞生了集群模式。
集群模式保留了主从复制的读并发能力,同时支持多主节点来解决写并发问题,另外集群中所有节点通过互相定时检测来实现高可用性(主节点故障则对应从节点重新选举替换主节点)。
¶高并发实现
¶哈希槽分片
由上文已经知道主从复制模式解决了读并发,为了解决写并发问题,cluster集群将写操作的数据根据key分配到不同的主节点中,而这个分配规则即“哈希槽分片”。
cluster集群的是采用“虚拟哈希槽分区”的方式进行分片存储的,它将整个数据库分为16384个槽位slot,所有key-value数据都存储在这些slot中的某一个上。一个slot槽位可以存放多个数据,key的槽位计算公式为:slot_number=crc16(key)%16384,其中crc16为16位的循环冗余校验和函数。

每一个主节点集群(主节点和其从节点组成的小集群)都负责维护一部分槽以及槽所映射的键值数据(也就是说集群中不是每个节点都保存有所有的数据,每个主节点只负责一部分槽对应的数据存储,所有的主节点存储的数据合起来才是整个集群的数据)。扩容或缩容以后,槽需要重新分配,数据也需要重新迁移,但是服务不需要下线。
由于Redis集群无中心节点,客户端请求会随机发给任意主节点;主节点只会处理自己负责槽位的命令请求,对于其它槽位的命令请求该主节点会返回客户端一个转向错误,客户端再根据错误中包含的地址和端口重新向正确负责对应槽位的主节点发起命令请求。
¶高可用实现
¶Gossip协议
Redis Cluster实例间以Gossip协议进行通信的机制。Redis Cluster运行时,各实例间需要通过PING、PONG消息进行信息交换,这些心跳消息包含了当前实例和部分其它实例的状态信息,以及Slot分配信息。这种通信机制有助于Redis Cluster中的所有实例都拥有完整的集群状态信息,从而能够实现高可用。
扩容注意事项:
随着集群规模的增加,实例间的通信量也会增加。如果我们盲目地对Redis Cluster进行扩容,就可能会遇到集群性能变慢的情况。这是因为,集群中大规模的实例间心跳消息会挤占集群处理正常请求的带宽。而且,有些实例可能因为网络拥塞导致无法及时收到PONG消息,每个实例在运行时会周期性地(每秒10次)检测是否有这种情况发生,一旦发生,就会立即给这些PONG消息超时的实例发送心跳消息。集群规模越大,网络拥塞的概率就越高,相应的,PONG消息超时的发生概率就越高,这就会导致集群中有大量的心跳消息,影响集群服务正常请求。
最后,我也给你一个小建议,虽然我们可以通过调整cluster-node-timeout配置项减少心跳消息的占用带宽情况,但是,在实际应用中,如果不是特别需要大容量集群,我建议你把Redis Cluster 的规模控制在400~500个实例。
假设单个实例每秒能支撑8万请求操作(8万QPS),每个主实例配置1个从实例,那么,400~ 500个实例可支持 1600万~2000万QPS(200/250个主实例*8万QPS=1600/2000万QPS),这个吞吐量性能可以满足不少业务应用的需求。
¶节点故障判断
集群中的每个节点都会定期向其他节点发送ping命令,如果接受ping消息的节点在指定时间内没有回复pong,则发送ping的节点就把接受ping的节点标记为主观下线。
如果集群半数以上的主节点都将主节点A标记为主观下线,则节点A将被标记为客观下线(通过节点的广播)即下线。
¶故障转移
当一个从节点发现自己正在复制的主节点进入了已下线状态时,从节点将开始对下线主节点进行故障转移,以下是故障转移执行的步骤:
- 故障的主节点对应的所有从节点进行选举,选举出一个成为新的主节点;
- 新的主节点会撤销所有对已下线主节点的槽指派,并将这些槽全部指派给自己;
- 新的主节点向集群广播一条PONG消息,这条PONG消息可以让集群中的其他节点立即知道这个节点已经由从节点变成了主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽。
- 新的主节点开始接收和自己负责处理的槽有关的命令请求,故障转移完成。
¶Cluster限制
cluster集群模式和单机模式下从使用上来看是由一些区别的:
1、需要客户端的支持(目前jedis、Lettuce、redisson等都有支持)
2、只支持一个数据库。单机模式Redis 默认自带有16个数据库,即db0~db15. 但是 Redis Cluster 集群架构下只有一个数据库空间,即db0,select 命令就不能用了,但实际也很少有人使用多数据库,所以这个限制并没什么影响。
3、多key操作受限(日常使用中最大的限制)。Redis Cluster要求,同一个redis操作多个key时需要这些key都在同一个slot时才能执行,否则报错。DEL删除多个key、SUNION、事务、LUA脚本等操作都可能有多key操作受限问题。
多key操作受限解决方案:
Redis Cluster提供了一个hash tag的机制,可以让我们把一组key映射到同一个 slot。
例如:user1000.following 这个 key 保存用户 user1000 关注的用户;user1000.followers 保存用户 user1000 的粉丝。
这两个 key 有一个共同的部分 user1000,可以指定对这个共同的部分做 slot 映射计算,这样他们就可以在同一个槽中了。
使用方式:
{user1000}.following 和 {user1000}.followers
就是把共同的部分使用 { } 包起来,计算 slot 值时,如果发现了花括号,就会只对其中的部分进行计算。
¶优缺点
优点
- 无中心架构;
- 可扩展性,数据按照 Slot 存储分布在多个节点,节点间数据共享,节点可动态添加或删除,可动态调整数据分布;
- 高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本。
- 实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave 到 Master 的角色提升。
缺点
- 数据通过异步复制,无法保证数据强一致性;
- 集群环境搭建复杂,不过基于 Docker 的搭建方案会相对简单。
- 存在一些使用限制。比如支持一个数据库、多key操作受限等。
¶部署安装
¶环境准备
redis要求至少三主三从共6个节点才能组成redis集群,可以分布在一台或者多台主机上。
假设有两台服务器用于搭建Redis Cluster集群。两台服务器的IP分别是:
192.168.102.111
192.168.102.112
每个服务器跑三个不同端口(6371、6372、6373)的redis服务进程,那么就能在这两台服务器中搭建出6个redis节点出来。为了简化部署过程,这里通过使用redis配置模板文件和docker compose来简化搭建过程。
¶创建redis配置模板文件
每台服务器都执行如下操作:
1 | mkdir -p /opt/redis/conf |
每台服务器都执行如下操作,另外注意下面clusterIp的修改(每台服务器ip不一样):
1 | #节点的密码 |
¶创建docker compose配置文件
每台服务器都执行如下操作
1 | vim /opt/redis/docker-compose.yml |
内容如下:
1 | # 描述 Compose 文件的版本信息 |
💁♂ 按照 Redis 官网:https://redis.io/topics/cluster-tutorial 的提示,为了使 Docker 与 Redis Cluster 兼容,推荐使用 Docker 的
host
网络模式。但这里发现不用也能支持,如果发现有网络上的问题可以改试host模式。另外使用host模式注意关闭宿主机防火墙。
每台服务器都执行如下操作创建并启动所有服务容器
1 | docker-compose up -d |
¶初始化并创建集群
首先确保两台服务器之间可以互相通信,然后选择任意一台并登录进一个redis服务,并通过redis客户端命令来初始化创建出一个Cluster集群。
1 | # 进入容器 |
查看集群状态、信息和节点信息
1 | # 进入容器 |
¶集群扩容
假又增加一台服务器192.168.60.203,并且启动了一个端口为6371的redis节点,现在希望把它加入到集群中,可如下操作:
1 | #新增一个节点(默认是主节点的方式加入),将新节点介绍给集群中的任意一个,那么整个集群的所有节点就能与新节点互相认识 |
1 | root@bogon:/data# redis-cli -a 123456 --cluster reshard 192.168.60.203:6371 |
¶集群模式常用命令
1 | #在集群中使用keys *,只会返回当前会话所在的单个节点的key,并非整个集群的key |
¶参考
https://juejin.cn/post/6868426752789020685
https://juejin.cn/post/6870674824247640072
https://www.cnblogs.com/cqming/p/11191079.html
https://blog.csdn.net/weixin_36691991/article/details/125868968