文档:https://redis.com.cn/topics/why-use-redis.html
1.我们为什么一定要用 Redis 呢?
速度快,完全基于内存,使用 C 语言实现,网络层使用 epoll 解决高并发问题,单线程模型避免了不必要的上下文切换及竞争条件;
注意:单线程仅仅是说在网络请求这一模块上用一个请求处理客户端的请求,像持久化它就会重开一个线程/进程去进行处理。
2.丰富的数据类型
Redis 有 8 种数据类型,当然常用的主要是 String、Hash、List、Set、 SortSet 这 5 种类型,他们都是基于键值的方式组织数据。
String:
SET name "redis.com.cn"
OK
GET name
"redis.com.cn"
Hash:将字段和值存到一个哈希键user:1中 并按顺序将字段和值输出
HMSET user:1 username ajeet password redis alexa 2000
OK
HGETALL user:1
"username"
"ajeet"
"password"
"redis"
"alexa"
"2000"
List:将java,sql...依次存入列表rediscomcn左侧
lpush rediscomcn java
(integer) 1
lpush rediscomcn sql
(integer) 1
lpush rediscomcn mongodb
(integer) 1
lpush rediscomcn cassandra
(integer) 1
lrange rediscomcn 0 10
"cassandra"
"mongodb"
"sql"
"java"
有序set:要求唯一,但取出顺序是随机的
sadd tutoriallist redis
(integer) 1
redis 127.0.0.1:6379> sadd tutoriallist sql
(integer) 1
redis 127.0.0.1:6379> sadd tutoriallist postgresql
(integer) 1
redis 127.0.0.1:6379> sadd tutoriallist postgresql
(integer) 0
redis 127.0.0.1:6379> sadd tutoriallist postgresql
(integer) 0
redis 127.0.0.1:6379> smembers tutoriallist
1) "redis"
2) "postgresql"
3) "sql"
有序set:
redis 127.0.0.1:6379> zadd tutoriallist 0 redis
(integer) 1
redis 127.0.0.1:6379> zadd tutoriallist 0 sql
(integer) 1
redis 127.0.0.1:6379> zadd tutoriallist 0 postgresql
(integer) 1
redis 127.0.0.1:6379> zadd tutoriallist 0 postgresql
(integer) 0
redis 127.0.0.1:6379> zadd tutoriallist 0 postgresql
(integer) 0
redis 127.0.0.1:6379> ZRANGEBYSCORE tutoriallist 0 10
1) "postgresql"
2) "redis"
3) "sql"
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
redis 127.0.0.1:6379> PFADD rediscomcn "redis"
1) (integer) 1
redis 127.0.0.1:6379> PFADD rediscomcn "mongodb"
1) (integer) 1
redis 127.0.0.1:6379> PFADD rediscomcn "mysql"
1) (integer) 1
redis 127.0.0.1:6379> PFCOUNT rediscomcn
(integer) 3
3.redis执行:
PING:redis是否启动 :本机/远程
$redis-cli -h 127.0.0.1 -p 6379 -a "mypass"
redis 127.0.0.1:6379>
redis 127.0.0.1:6379> PING
PONG
4.键与值:
redis.com.cn 是值,DEL后返回1,若键mykey还存在,则返回0
redis 127.0.0.1:6379> SET mykey redis.com.cn
OK
redis 127.0.0.1:6379> DEL mykey
(integer) 1
5.消息队列:
Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。
简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。
而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。
Redis Stream 是 Redis 5.0 版本新增加的数据结构。
向队列中添加消息:XADD:
redis> XADD mystream * name Sara surname OConnor
"1601372323627-0"
redis> XADD mystream * field1 value1 field2 value2 field3 value3
"1601372323627-1"
redis> XLEN mystream
(integer) 2
redis> XRANGE mystream - +
1) 1) "1601372323627-0"
2) 1) "name"
2) "Sara"
3) "surname"
4) "OConnor"
2) 1) "1601372323627-1"
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
5) "field3"
6) "value3"
redis>
对消息长度进行限制:XTRIM:
返回值 (integer) 0
表示没有消息被修剪(或删除)。即消息列表长度没有超过MAXLEN
127.0.0.1:6379> XADD mystream * field1 A field2 B field3 C field4 D
"1601372434568-0"
127.0.0.1:6379> XTRIM mystream MAXLEN 2
(integer) 0
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1601372434568-0"
2) 1) "field1"
2) "A"
3) "field2"
4) "B"
5) "field3"
6) "C"
7) "field4"
8) "D"
127.0.0.1:6379>
redis>
删除消息:XDEL:
127.0.0.1:6379> XADD mystream * a 1
1538561698944-0
127.0.0.1:6379> XADD mystream * b 2
1538561700640-0
127.0.0.1:6379> XADD mystream * c 3
1538561701744-0
127.0.0.1:6379> XDEL mystream 1538561700640-0
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) 1538561698944-0
2) 1) "a"
2) "1"
2) 1) 1538561701744-0
2) 1) "c"
2) "3"
获取消息队列长度:XLEN:
redis> XADD mystream * item 1
"1601372563177-0"
redis> XADD mystream * item 2
"1601372563178-0"
redis> XADD mystream * item 3
"1601372563178-1"
redis> XLEN mystream
(integer) 3
redis>
->获取部分消息:XRANGE:
命名:
writers
和mystream
只是不同的键名,用于区分不同的数据流。writers
听起来更具体,暗示存储的是作家信息,而mystream
是一个更通用的名称。
redis> XADD writers * name Virginia surname Woolf
"1601372577811-0"
redis> XADD writers * name Jane surname Austen
"1601372577811-1"
redis> XADD writers * name Toni surname Morrison
"1601372577811-2"
redis> XADD writers * name Agatha surname Christie
"1601372577812-0"
redis> XADD writers * name Ngozi surname Adichie
"1601372577812-1"
redis> XLEN writers
(integer) 5
redis> XRANGE writers - + COUNT 2
1) 1) "1601372577811-0"
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) "1601372577811-1"
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
redis>
->读取不同数据流:XREAD:
redis> XREAD COUNT 2 STREAMS mystream writers 0-0 0-0
1) 1) "mystream"
2) 1) 1) 1526984818136-0
2) 1) "duration"
2) "1532"
3) "event-id"
4) "5"
5) "user-id"
6) "7782813"
2) 1) 1526999352406-0
2) 1) "duration"
2) "812"
3) "event-id"
4) "9"
5) "user-id"
6) "388234"
2) 1) "writers"
2) 1) 1) 1526985676425-0
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) 1526985685298-0
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
->获取全部信息:
redis 127.0.0.1:6379> ping
PONG
redis 127.0.0.1:6379> AUTH "password"
(error) ERR Client sent AUTH, but no password is set
redis 127.0.0.1:6379> PING
PONG
redis 127.0.0.1:6379> ECHO "Welcome to rediscomcn"
"Welcome to rediscomcn"
redis 127.0.0.1:6379> INFO
6.Redis事务:
去银行办理业务,可以选择一次性办理所有业务:Redis 执行
EXEC
命令也可以先取号,等待办理:你用
MULTI
开始一个事务,然后你可以输入很多命令,这些命令不会立即执行,而是被放入一个“等待执行”的列表中。当你输入EXEC
命令时,所有这些命令就会一次性执行。QUEUED 的字样,这表示我们在用 MULTI 组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现 QUEUED 则表示我们这个命令成功插入了缓存队列AOF持久化:
在 Redis 中,AOF 持久化会记录你执行的每个写命令(比如添加数据或修改数据)。如果 Redis 服务器关闭或出现故障,你可以查看 AOF 文件来恢复数据。
修复 AOF 文件:
写电子日记,帮你记录日常,但是若不能自动保存或突然断网断电,有些内容没保存上,用
redis-check-aof
的工具来“修复”这个文件,它会移除那些不完整的记录,确保 AOF 文件是完整和可用的。
当消息中无内容时,返回empty list or set
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> EXEC
(empty list or set)
redis 127.0.0.1:6379> MULTI
OK
redis 127.0.0.1:6379> SET rediscomcn redis
QUEUED
redis 127.0.0.1:6379> GET rediscomcn
QUEUED
redis 127.0.0.1:6379> INCR visitors
QUEUED
redis 127.0.0.1:6379> EXEC
1) OK
2) "redis"
3) (integer) 1
Redis事务错误:
在EXEC之前出错,redis 会拒绝执行这一事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379> haha //一个明显错误的指令
(error) ERR unknown command 'haha'
127.0.0.1:6379> ping
QUEUED
127.0.0.1:6379> exec
//redis无情的拒绝了事务的执行,原因是“之前出现了错误”
(error) EXECABORT Transaction discarded because of previous errors.
在EXEC之后出错,redis 会选择忽视:
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 23
QUEUED
//age不是集合,所以如下是一条明显错误的指令
127.0.0.1:6379> sadd age 15
QUEUED
127.0.0.1:6379> set age 29
QUEUED
127.0.0.1:6379> exec //执行事务时,redis不会理睬第2条指令执行错误
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"29" //可以看出第3条指令被成功执行了
WATCH:
监视KEY是否修改,若修改,调用EXEC时,返回nil
127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> watch age //开始监视age
OK
127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec //触发EXEC
(nil) //事务无法被执行
7.Redis 数据库的备份
save:进行备份,它将在 Redis 目录中创建 备份文件:dump.rdb 。
CONFIG get dir:找到redis所在目录,将备份移到该目录下 +启动服务器->恢复redis数据
BGSAVE:启动备份并在后台运行
8.设置密码
客户端:
-CONFIG get command:查看是否有密码
-CONFIG set requirepass "":设置密码
-CONFIG get requirepass:此时需要密码才能登录,显示NOAUTH Authentication required
-AUTH:验证密码是否正确
127.0.0.1:6379> AUTH "rediscomcn123" OK 127.0.0.1:6379> SET mykey "hindi100" OK 127.0.0.1:6379> GET mykey "hindi100" 127.0.0.1:6379>
服务器端:
Redis服务器默认不受密码保护,也就是没有设置密码。
1.通过命令行设置:
-auth password:是否有密码
-CONFIG SET requirepass "":设置密码
requirepass 是用于更改密码的配置参数,设置密码实时生效。 重启失效,用永久生效需要保存设置到配置文件。
-CONFIG REWRITE:保存更改
-重启生效
2.通过redis.conf文件设置:
# requirepass foobared
需求注释,设置密码未1234567
requirepass 123467
保存文件。
重新启动或停止并启动服务器以重新加载更改。
9.Redis Pipelining 流水线
为什么Redis是TCP服务器?
跨平台和跨语言:TCP是互联网上最通用的协议之一,几乎所有编程语言都支持TCP编程。通过TCP,Redis可以轻松与各种客户端(如Python、Java、Node.js等)进行通信。
可靠性:TCP协议的可靠性和面向连接的特性,确保了数据传输的完整性和准确性,这对于数据库操作非常重要。
高效性:Redis结合了TCP协议和高效的I/O多路复用技术,能够处理高并发的客户端请求。
什么是TCP协议?
TCP(Transmission Control Protocol,传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。它的主要特点包括:
面向连接:在通信开始之前,客户端和服务器之间需要建立一个连接(三次握手)。通信结束后,连接会被释放(四次挥手)。
可靠传输:TCP通过序列号、确认应答(ACK)、超时重传等机制,确保数据能够完整、准确地传输到对方。如果数据丢失或损坏,TCP会自动重传。
基于字节流:TCP将数据视为字节流,不保留消息边界。这意味着发送方发送的多个小消息可能会被接收方合并为一个大消息,反之亦然。
拥塞控制:TCP通过动态调整发送窗口大小,避免网络拥塞。
什么是流水线
流水线操作有助于客户端向服务器发送多个请求,而无需等待回复,最后只需一步即可读取回复
10.redis分区
它通常用于大型数据库:我现在有3000个用户,0-1000是svip,1001-2000是vip,2001-3000是普通用户
- 范围分区
- 哈希分区
分区存在一些缺点,因为 Redis 的某些功能受到分区的阻碍。
- 分区通常不支持具有多个键的操作。例如,如果两个集合存储在映射到不同 Redis 实例的键中,则无法执行它们之间的交集。
- 分区不支持具有多个 key 的事务。
- 分区粒度是关键,因此不可能使用单个巨大的 key(如非常大的有序集)对数据集进行分片。
- 使用分区时,数据处理更复杂,例如,您必须处理多个 RDB / AOF 文件,并且需要从多个实例和主机聚合持久性文件来备份数据。
- 添加和删除容量可能很复杂。例如,Redis Cluster 支持大多数透明的数据重新平衡,能够在运行时添加和删除节点,但客户端分区和代理等其他系统不支持此功能。然而,一种称为预分片的技术在这方面有所帮助。
11.java+redis
12.面试
什么是Redis?
传统数据库遵循 ACID 规则。而 Nosql(Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称) 一般为分布式而分布式一般遵循 CAP 定理。与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存,每秒可以处理超过 10 万次读写操作,是已知性能最快的 Key-Value 数据库。另外,Redis 也经常用来做分布式锁。除此之外,Redis 支持事务、持久化、LUA 脚本、LRU 驱动事件、多种集群方案。
分布式锁:因为 Redis 是基于内存的,操作速度非常快,而且它支持原子操作(即操作要么全部成功,要么全部失败,不会出现中间状态),这使得它非常适合用来实现分布式锁。
假设你和你的朋友都想买同一件商品,库存只有 1 件。
你和你的朋友的手机(代表不同的服务器)同时向 Redis 发起“获取锁”的请求。
Redis 检查后发现锁没有被占用,于是给了你手机一个“锁”,并设置了 10 秒的过期时间。
你手机拿到锁后,开始操作数据库,把库存从 1 减到 0。
操作完成后,你手机通知 Redis 释放锁。
这时候,你的朋友的手机再发起请求时,就会发现锁已经被占用,只能等待。
什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?
持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。Redis 提供了两种持久化方式:RDB(默认) 和AOF
RDB:
rdb是Redis DataBase缩写
功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数
AOF:
Aof是Append-only file缩写