Redis学习

Redis学习

笔记来源:狂神说Redis

下图来自百度百科

image-20230715103709705

Redis在支持语言方面是及时扩充中,它已经支持多种语言,包括C、C ++、Java、Python、PHP、Perl、Ruby等,它也支持在应用程序中直接使用Redis,而不需要进行任何改变,这种特性使Redis成为了一种适用于开发的非常好的数据库。

Redis可以周期性地将更新的数据写入磁盘,并将修改操作写入追加的记录文件,以保证数据的持久化。这样即使服务器重启,数据也不会丢失。

Redis还支持主从同步。主节点负责处理所有写入操作,而从节点则复制主节点的数据并处理读取请求

此外,Redis是一种免费且开源的NoSQL技术。它被广泛使用于许多应用场景,被誉为一种高性能的结构化数据库

Redis能干嘛?

  1. 内存存储、持久化,内存中是断电即失、所以说持久化很重要(rdb、aof)
  2. 效率高,可以用于告诉缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器、计数器(浏览量)

Redis的安装

Reids的官网

英文网:https://redis.io/

中文网:http://www.redis.cn/

Windows安装

第一步:下载安装包

下载地址

image-20230715143545484

第二步:解压

image-20230715143843511

第三步:开启Redis(双击redis-server即可)

image-20230715144027909

第四步:使用redis客户端连接redis(双击redis-cli)

image-20230715144349730

测试

image-20230715144638023

此时你就可以与 Redis 进行通信了

RedisInsight :Redis 官方可视化工具下载

第一步:下载

下载地址

第二步:安装

image-20230715150025606

第三步:添加redis数据库

在添加之前你要确保你redis服务启动了

image-20230715150117629

image-20230715150539385

image-20230715150443459

image-20230715151349768

image-20230715151455716

image-20230715151620579

image-20230715151726315

image-20230715151804184

image-20230715151843247

image-20230715151947971

image-20230715152240045

Linux安装

第一步:安装依赖

[root@redis-server ~]# yum install -y gcc

第二步:下载安装包

下载地址

[root@redis-server ~]# wget https://download.redis.io/releases/redis-7.0.9.tar.gz
[root@redis-server ~]# ls
anaconda-ks.cfg  redis-7.0.9.tar.gz

第三步:解压

[root@redis-server ~]# mkdir /usr/java/
[root@redis-server ~]# tar -zxf redis-7.0.9.tar.gz -C /usr/java/
[root@redis-server ~]# cd /usr/java/
[root@redis-server java]# ls
redis-7.0.9

第四步:编译安装

[root@redis-server java]# cd redis-7.0.9/
[root@redis-server redis-7.0.9]# ls
00-RELEASENOTES     CONTRIBUTING.md  INSTALL    README.md   runtest-cluster    SECURITY.md    tests
BUGS                COPYING          Makefile   redis.conf  runtest-moduleapi  sentinel.conf  TLS.md
CODE_OF_CONDUCT.md  deps             MANIFESTO  runtest     runtest-sentinel   src            utils

# 可以看到这个包里面以及有了Makefile 我们直接make && mkae install 编译即可
[root@redis-server redis-7.0.9]# make && make install

# 安装完成以后搜索一下看看他在哪,因为我们没有指定安装路径
[root@redis-server redis-7.0.9]# find / -name redis-server
/usr/local/bin/redis-server
/usr/java/redis-7.0.9/src/redis-server
[root@redis-server redis-7.0.9]# cd /usr/local/bin/
[root@redis-server bin]# ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server

第五步:修改配置文件redis.conf

[root@redis-server bin]# find / -name redis.conf
/usr/java/redis-7.0.9/redis.conf
# 把redis.conf的redis配置文件移动到当前目录,方便我们配置
[root@redis-server bin]# cp -rf /usr/java/redis-7.0.9/redis.conf ./
[root@redis-server bin]# ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis.conf  redis-sentinel  redis-server

[root@redis-server bin]# vim redis.conf 
# 修改如下内容
bind 0.0.0.0   # 运行远程访问
daemonize yes  # 设置后台启动
requirepass 000000 # 设置redis登录密码

第六步:查看端口并放行端口6379

[root@redis-server bin]# ./redis-server redis.conf 
[root@redis-server bin]# netstat -tlnp |grep 6379
tcp      0     0 0.0.0.0:6379       0.0.0.0:*     LISTEN      35430/./redis-serve 
[root@redis-server bin]# firewall-cmd --add-port=6379/tcp --permanent
success
[root@redis-server bin]# firewall-cmd --reload
success

第七步:启动redis并指定redis.conf文件

# 启动redis-cli连接redis-server
[root@redis-server bin]# ./redis-cli -h 192.168.200.10 -p 6379 -a 000000
192.168.200.10:6379> ping
PONG
192.168.200.10:6379> set name csq
OK
192.168.200.10:6379> get name
"csq"

第八步:使用RedisInsight远程连接redis

image-20230715162757206

image-20230715161724516

image-20230715162138662

可以看到以及查询到了我们刚刚设置的值

如何关闭redis呢?

[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli 
127.0.0.1:6379> auth 000000
OK
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> shutdown
not connected> exit
[root@redis-server bin]# ps -ef |grep redis
root      88157  12050  0 16:35 pts/0    00:00:00 grep --color=auto redis

测试性能

redis-benchmark是Redis自带的基准测试工具,用于测试Redis服务器的性能。它可以通过模拟并发的客户端请求来评估Redis的性能指标,例如每秒处理请求数、平均响应时间等。

在执行基准测试时,可以指定以下参数:

选项描述默认值
-h指定服务器主机名127.0.0.1
-p指定服务器端口6379
-s指定服务器 socket
-c指定并发连接数50
-n指定请求数10000
-d以字节的形式指定SET/GET 值的数据大小
-k1=keep alive 0=reconnect1
-rSET/GET/INCR使用随机 key, SADD 使用随机值
-P通过管道传输 < numreq > 请求1
-q强制退出 redis。仅显示 query/sec 值
-csv以 CSV 格式输出
-t仅运行以逗号分隔的测试命令列表
-l(小写L)生成循环,永久执行测试
-I(大写I)Idle 模式。仅打开 N 个 idle 连接并等待

测试本机,端口为6379,50台机器,一万条数据的操作

[root@redis-server bin]# redis-benchmark -h localhost -a 000000 -p 6379 -c 50 -n 10000

image-20230716111124398

Redis基础知识

redis默认有16个数据库

默认使用的是第0个数据库

可以查看redis.conf配置文件

image-20230716112052160

可以使用select进行切换数据库

localhost:6379> select 2   # 切换2号数据库
OK 
localhost:6379[2]> dbsize  # 查看数据库大小
(integer) 0
localhost:6379[2]> select 16      # 因为是从第0数据库开始到第15号数据库
(error) ERR DB index is out of range
localhost:6379[2]> select 15      # 切换到了15号数据库
OK
localhost:6379[15]> 

查看所有的key

localhost:6379[15]> select 3     # 切换数据库
OK
localhost:6379[3]> set name csq  # 定义name
OK
localhost:6379[3]> keys *        # 查看所有的key
1) "name"
localhost:6379[3]> select 15     # 切换到第15号数据库
OK
localhost:6379[15]> keys *       # 是查询不到的
(empty array)
localhost:6379[15]> select 3
OK

清除当前数据库内容

localhost:6379[3]> flushdb       # 清空此数据库信息
OK
localhost:6379[3]> keys *        # 查看所有的key
(empty array) 

清除所有数据库内容

localhost:6379> select 3
OK
localhost:6379[3]> keys *
(empty array)
localhost:6379[3]> set name zzz    # 定义名字
OK
localhost:6379[3]> select 2
OK
localhost:6379[2]> set name ccc    # 定义名字
OK
localhost:6379[2]> flushall        # 清除所有数据库
OK
localhost:6379[2]> keys *          # 数据库2查询不到定义的内容了
(empty array)
localhost:6379[2]> select 3
OK
localhost:6379[3]> keys *          # 数据库3也是查询不到了
(empty array)

Redis为什么单线程还可以这么快?

非阻塞IO模型:Redis采用了非阻塞IO模型,通过使用事件驱动的方式处理客户端请求。它使用高效的事件驱动库(如epoll、kqueue等)来监听和处理网络事件,能够同时处理多个客户端请求,提高了系统的并发处理能力。

避免线程切换开销:多线程的并发模型会涉及线程的切换和上下文切换开销,而Redis的单线程模型避免了这些开销。线程切换和上下文切换会耗费CPU资源和时间,影响系统的响应速度。由于Redis是单线程的,它能够更高效地利用CPU资源来处理请求。

内存操作效率高:Redis的数据存储在内存中,而内存的读写速度远高于磁盘和网络的读写速度。因此,Redis能够快速地读取和写入数据,提高系统的响应速度。

五大数据类型

下图来自redis中文网

image-20230716114920436

Redis命令查询地址

字符串String

在Redis中,字符串(String)是最基本的数据类型之一,用于存储字符串整数和浮点数等

存储值、获取值、删除值、判断值是否存在

Redis字符串的值可以是字符串、整数或浮点数

localhost:6379> SET name chenshiren     # 存储字符串
OK
localhost:6379> GET name                # 获取字符串
"chenshiren"
localhost:6379> SET Name csq
OK
localhost:6379> GET Name        # 可以看到redis设置的值是区分大小写的
"csq"
localhost:6379> SET age 18      # 整数
OK
localhost:6379> GET age
"18"
localhost:6379> SET Age 18.55   # 浮点数
OK
localhost:6379> GET Age
"18.55"
localhost:6379> SET Age 19.55   # 如果key已经存在,SET命令会覆盖原有的值
OK
localhost:6379> GET Age
"19.55"
localhost:6379> DEL Age         # 删除值
(integer) 1
localhost:6379> GET Age        
(nil)                           # 输出为nil表示已经删除了
localhost:6379> EXISTS Age      # 判断Age键是否存在
(integer) 0                     # 返回0不存在
localhost:6379> EXISTS name
(integer) 1                     # 返回1存在

# Redis默认输出是不支持中文的
localhost:6379> SET Age 18岁
OK
localhost:6379> GET Age
"18\xe5\xb2\x81"
# 把中文换成了二进制的形式

localhost:6379> quit  # 先退出redis
# 然后再进入redis-cli 加上 --raw 参数即可显示原始内容
[root@redis-server bin]# redis-cli -h localhost -p 6379 -a 000000 --raw
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
localhost:6379> GET Age
18

字符串长度与追加字符串

使用STRLEN命令获取字符串的长度

使用APPEND命令将字符串追加到已有值的末尾。

127.0.0.1:6379> SET key1 csq             # 设置可以的值为csq
OK
localhost:6379> STRLEN key1              # 获取字符串长度
6
localhost:6379> APPEND key1 zzzzzzz      # 追加字符串zzzzzz到key1
13
localhost:6379> STRLEN key1              # 获取字符串长度
13 
localhost:6379> GET key1                 # 查看key1的值
csqzzzzzzzzzz

获取子串

获取子串:使用GETRANGE命令获取字符串的子串。

127.0.0.1:6379> SET name chenshiren
OK
127.0.0.1:6379> get name
"chenshiren"
127.0.0.1:6379> GETRANGE name 0 3 # 获取字符串第0个到第3个子串
"chen"
127.0.0.1:6379> GETRANGE name 0 -1
"chenshiren"
# 在Redis中结束位置为-1表示获取到字符串的末尾

覆盖

使用SETRANGE命令可以将字符串的一部分进行覆盖

127.0.0.1:6379> SET name2 aaabbbcccdddfffggg
OK
127.0.0.1:6379> GET name2
"aaabbbcccdddfffggg"
127.0.0.1:6379> SETRANGE name2 3 zzz
(integer) 18
127.0.0.1:6379> GET name2
"aaazzzcccdddfffggg"

查看数据库中的键(值)、删除数据库中的键(值)

localhost:6379> KEYS *   # * 代表查询所有的键
1) "name"
2) "age"
3) "Name"
localhost:6379> KEYS *me  # *me表示查询以me结尾的键
1) "name"
2) "Name"
localhost:6379> FLUSHALL  # 删除所有数据库中的键
OK 
localhost:6379> KEYS *    # 查看发现已经全部被删除(慎用!)
(empty array)

子串匹配和替换

使用GETSET命令可以获取并设置一个新的值,使用SETNX命令可以设置一个不存在的键。还可以使用MSETMGET命令一次性设置和获取多个键值对

127.0.0.1:6379> SET name chenshiren  # 设置name的值为chenshiren
OK
127.0.0.1:6379> GETSET name csq   # 获取name这个值并替换为csq如果没有值则不替换
"chenshiren"
127.0.0.1:6379> GET name          # 获取name的值
"csq"
127.0.0.1:6379> SETNX myname verygoodman # 设置一个不存在的键
(integer) 1
127.0.0.1:6379> GET myname               # 获取myname的值
"verygoodman"

127.0.0.1:6379> FLUSHALL                 # 清除所有数据库
OK
127.0.0.1:6379> MSET A 5 B 4 C 3 D 2 E 1 F 0  # 设置A B C D E F 的值
OK
127.0.0.1:6379> keys *                        # 查看所有键值
1) "B"
2) "D"
3) "F"
4) "A"
5) "E"
6) "C"
127.0.0.1:6379> MGET A B C D E                # 获取ABCDE 的值
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"

自增和自减操作

INCRDECR命令:自增和自减一个整数类型的字符串。

INCRBYDECRBY命令:自增和自减一个整数类型的字符串指定的增量或减量。

127.0.0.1:6379> SET number 0    # 设置number为0
OK
127.0.0.1:6379> INCR number     # 自增 1
(integer) 1
127.0.0.1:6379> GET number      # 查看number的值
"1"
127.0.0.1:6379> INCR number     # 继续自增
(integer) 2
127.0.0.1:6379> INCR number     # 继续自增
(integer) 3
127.0.0.1:6379> INCR number     # 继续自增
(integer) 4
127.0.0.1:6379> GET number      # 查看number的值
"4"
127.0.0.1:6379> DECR number     # 自减
(integer) 3  
127.0.0.1:6379> GET number      # 查看number的值
"3"

127.0.0.1:6379> INCRBY number 7 # number自增7
(integer) 10
127.0.0.1:6379> GET number      # 查看number的值
"10"
127.0.0.1:6379> DECRBY number 5 # number自减5
(integer) 5
127.0.0.1:6379> GET number      # 查看number的值
"5"

过期时间

可以为字符串类型的键设置过期时间,使用EXPIRETTL命令来设置和获取过期时间

localhost:6379> SET name chenshiren  # 设置一个键
OK  
localhost:6379> TTL name             # 查看过期时间
-1                                   # -1表示没有设置过期时间
localhost:6379> EXPIRE name 10       # 设置过期时间为10秒
1
localhost:6379> GET name             # 现在的值还没过期
chenshiren
localhost:6379> TTL name             # 还有9秒过期
9
localhost:6379> TTL name
-2                                   # -2 表示这个键已经过期
localhost:6379> GET name             # 查询不到了

列表List

列表(List)是一种有序的字符串集合,它可以包含各种类型的元素,如字符串、整数、浮点数等

存储的数据类型:Redis的列表类型以插入顺序存储元素允许重复的元素存在可以在列表的两端进行插入和删除操作

基本操作

理解左边插入元素与右边插入元素

image-20230717144034850

  • 前面插入元素:使用LPUSH命令将一个或多个元素插入到列表的左边

    127.0.0.1:6379> LPUSH myname csq1 csq2 csq3 csq4 csq5 csq6
    (integer) 6
    127.0.0.1:6379> LRANGE myname 0 -1
    1) "csq6"
    2) "csq5"
    3) "csq4"
    4) "csq3"
    5) "csq2"
    6) "csq1"
    
  • 后面插入元素:使用RPUSH命令将一个或多个元素插入到列表的右边

    127.0.0.1:6379> RPUSH myname zhw1 zhw2 zhw3 zhw4 zhw5 zhw6
    (integer) 12
    127.0.0.1:6379> LRANGE myname 0 -1
     1) "csq6"
     2) "csq5"
     3) "csq4"
     4) "csq3"
     5) "csq2"
     6) "csq1"
     7) "zhw1"
     8) "zhw2"
     9) "zhw3"
    10) "zhw4"
    11) "zhw5"
    12) "zhw6"
    
    
  • 前面弹出元素:使用LPOP命令从列表的左边弹出一个元素

    127.0.0.1:6379> LPOP myname 2
    1) "csq6"
    2) "csq5"
    127.0.0.1:6379> LRANGE myname 0 -1
     1) "csq4"
     2) "csq3"
     3) "csq2"
     4) "csq1"
     5) "zhw1"
     6) "zhw2"
     7) "zhw3"
     8) "zhw4"
     9) "zhw5"
    10) "zhw6"
    
    
  • 后面弹出元素:使用RPOP命令从列表的右边弹出一个元素

    127.0.0.1:6379> RPOP myname 2
    1) "zhw6"
    2) "zhw5"
    127.0.0.1:6379> LRANGE myname 0 -1
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "zhw1"
    6) "zhw2"
    7) "zhw3"
    8) "zhw4"
    
  • 获取元素:使用LRANGE命令获取列表中指定范围的元素

    127.0.0.1:6379> LRANGE myname 1 5
    1) "csq3"
    2) "csq2"
    3) "csq1"
    4) "zhw1"
    5) "zhw2"
    127.0.0.1:6379> LRANGE myname 0 -1
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "zhw1"
    6) "zhw2"
    7) "zhw3"
    8) "zhw4"
    
  • 获取列表长度:使用LLEN命令获取列表的长度

    127.0.0.1:6379> LLEN myname
    (integer) 8    # 长度为8
    
  • 在指定元素前或后插入元素:使用LINSERT命令在列表中指定元素的前或后插入一个元素

    127.0.0.1:6379> LRANGE myname 0 -1
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "zhw1"
    6) "zhw2"
    7) "zhw3"
    8) "zhw4"
    # 在csq1 的后面添加插入*******符号
    127.0.0.1:6379> LINSERT myname after csq1 ****************************** 
    (integer) 9
    127.0.0.1:6379> LRANGE myname 0 -1
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "******************************"
    6) "zhw1"
    7) "zhw2"
    8) "zhw3"
    9) "zhw4"
    # 在 zhw1 前面添加插入 zhw0 元素
    127.0.0.1:6379> LINSERT myname before zhw1 zhw0
    (integer) 10
    127.0.0.1:6379> LRANGE myname 0 -1
     1) "csq4"
     2) "csq3"
     3) "csq2"
     4) "csq1"
     5) "******************************"
     6) "zhw0"
     7) "zhw1"
     8) "zhw2"
     9) "zhw3"
    10) "zhw4"
    
  • 根据索引设置或获取元素:使用LSETLINDEX命令可以根据索引设置和获取列表中的元素

    127.0.0.1:6379> LRANGE myname 0 -1  # 查看所有元素
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "zhw1"
    6) "zhw2"
    7) "zhw3"
    8) "zhw4"
    127.0.0.1:6379> LINDEX myname 0  # 查看第0个元素
    "csq4"
    127.0.0.1:6379> LINDEX myname 1  # 查看第1个元素
    "csq3"
    
    127.0.0.1:6379> LSET myname 0  csq5 # 修改第0个元素为 csq5
    OK
    127.0.0.1:6379> LRANGE myname 0 -1  # 查看所有元素
    1) "csq5"
    2) "csq3"
    3) "csq2"
    4) "csq1"
    5) "zhw1"
    6) "zhw2"
    7) "zhw3"
    8) "zhw4"
    

范围操作

  • 移动元素:RPOPLPUSH命令用于将列表的最后边的元素弹出,并将弹出的元素插入到另一个列表的最前边
127.0.0.1:6379> LRANGE myname 0 -1
1) "csq1"
2) "zhw1"
127.0.0.1:6379> RPOPLPUSH myname MYNAME
"zhw1"
127.0.0.1:6379> LRANGE MYNAME 0 -1
1) "zhw1"
  • 截取列表:使用LTRIM命令截取列表,只保留指定范围内的元素
  127.0.0.1:6379> LRANGE myname 0 -1 # 查看所有元素
  1) "csq5"
  2) "csq3"
  3) "csq2"
  4) "csq1"
  5) "zhw1"
  6) "zhw2"
  7) "zhw3"
  8) "zhw4"
  127.0.0.1:6379> LTRIM myname 3 4   # 只保留 3 到 4 的元素
  OK
  127.0.0.1:6379> LRANGE myname 0 -1 # 查看所有元素
  1) "csq1"
  2) "zhw1"
  
  • 删除元素:使用LREM命令可以删除列表中指定数量的匹配元素
  127.0.0.1:6379> LREM myname 1 csq5  # 删除1个csq5元素
  (integer) 1
  127.0.0.1:6379> LRANGE myname 0 -1  # 查看所有元素
  1) "csq3"
  2) "csq2"
  3) "csq1"
  4) "zhw1"
  5) "zhw2"
  6) "zhw3"
  7) "zhw4"
  127.0.0.1:6379> LPUSH myname csq4 csq4 csq4 csq5  # 添加一堆元素
  (integer) 11
  127.0.0.1:6379> LRANGE myname 0 -1  # 查看所有元素
   1) "csq5"
   2) "csq4"
   3) "csq4"
   4) "csq4"
   5) "csq3"
   6) "csq2"
   7) "csq1"
   8) "zhw1"
   9) "zhw2"
  10) "zhw3"
  11) "zhw4"
  127.0.0.1:6379> LREM myname 3 csq4   # 删除3个csq4元素
  (integer) 3
  127.0.0.1:6379> LRANGE myname 0 -1   # 查看所有元素
  1) "csq5"
  2) "csq3"
  3) "csq2"
  4) "csq1"
  5) "zhw1"
  6) "zhw2"
  7) "zhw3"
  8) "zhw4"

集合Set

在Redis中,集合(Set)是一种无序且不重复的数据结构,它包含了多个元素,每个元素都是唯一的。

基本操作

  • 添加元素:使用SADD命令向集合中添加一个或多个元素

    127.0.0.1:6379> sadd myset csq1 csq2  # 添加元素csq1 csq2
    (integer) 2
    127.0.0.1:6379> SMEMBERS myset        # 查看集合中的元素
    1) "csq2"
    2) "csq1"
    
  • 删除元素:使用SREM命令从集合中删除一个或多个元素

    127.0.0.1:6379> SMEMBERS myset   # 查看集合中的元素
    1) "csq2"
    2) "csq1"
    127.0.0.1:6379> SREM myset csq1  # 删除myset集合中的 csq1 元素
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset   # 查看集合中的元素
    1) "csq2"
    
  • 随机删除元素:使用SPOP命令从集合中随机删除一个元素或多个元素

    127.0.0.1:6379> SMEMBERS myset  # 查看myset集合中的元素
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq5"
    5) "csq6"
    6) "csq7"
    127.0.0.1:6379> SPOP myset 1   # 随机删除myset集合中的一个元素
    1) "csq3"
    127.0.0.1:6379> SPOP myset 2   # 随机删除myset集合中的两个元素
    1) "csq6"
    2) "csq2"
    127.0.0.1:6379> SMEMBERS myset # 查看myset集合中的元素
    1) "csq5"
    2) "csq4"
    3) "csq7"
    
  • 获取集合中的所有元素:使用SMEMBERS命令获取集合中的所有元素

    127.0.0.1:6379> SMEMBERS myset  # 
    1) "csq2"
    
  • 判断元素是否在集合中:使用SISMEMBER命令判断一个元素是否在集合中

    127.0.0.1:6379> SMEMBERS myset       # 查看集合中的元素
    1) "csq2"
    127.0.0.1:6379> SISMEMBER myset csq2 # 判断 myset集合中的 csq2 元素是否存在
    (integer) 1  # 1为存在
    127.0.0.1:6379> SISMEMBER myset csq1 # 判断 myset集合中的 csq1 元素是否存在
    (integer) 0  # 0为不存在
    
  • 获取集合中元素的数量:使用SCARD命令获取集合中元素的数量

    127.0.0.1:6379> SMEMBERS myset  # 查看myset元素
    1) "csq2"
    127.0.0.1:6379> SADD myset csq3 csq4 csq5 csq6 csq7 # 添加myset的元素
    (integer) 5
    127.0.0.1:6379> SCARD myset     # 查看元素数量
    (integer) 6
    127.0.0.1:6379> SMEMBERS myset  # 查看myset元素
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq5"
    5) "csq6"
    6) "csq7"
    
  • 随机获取集合中的元素:使用SRANDMEMBER命令随机获取集合中的一个或多个元素

    127.0.0.1:6379> SMEMBERS myset
    1) "csq4"
    2) "csq3"
    3) "csq2"
    4) "csq5"
    5) "csq6"
    6) "csq7"
    127.0.0.1:6379> SRANDMEMBER myset 1  # 随机获取一个myset集合中的元素
    1) "csq7"
    127.0.0.1:6379> SRANDMEMBER myset 1  # 随机获取一个myset集合中的元素
    1) "csq4"
    127.0.0.1:6379> SRANDMEMBER myset 1  # 随机获取一个myset集合中的元素
    1) "csq5"
    127.0.0.1:6379> SRANDMEMBER myset 2  # 随机获取两个myset集合中的元素
    1) "csq4"
    2) "csq3"
    127.0.0.1:6379> SRANDMEMBER myset 2  # 随机获取两个myset集合中的元素
    1) "csq5"
    2) "csq2"
    
  • 移动元素:将一个指定的值,移动到另外一个set集合

    127.0.0.1:6379> FLUSHdb        # 清空当前数据库
    OK
    127.0.0.1:6379> SADD myset1 csq1 csq2 csq3 csq4 csq5  # 添加myset1元素
    (integer) 5
    127.0.0.1:6379> SADD myset2 zhw1 zhw2 zhw3 zhw4 zhw5  # 添加myset2元素
    (integer) 5
    127.0.0.1:6379> SMOVE myset2 myset1 zhw1  # 将myset2中的zhw1 移动到没myset1中
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset1  # 查看myset1
    1) "csq3"
    2) "csq2"
    3) "csq1"
    4) "csq5"
    5) "csq4"
    6) "zhw1"
    
  • 获取多个集合的交集、并集、差集:使用SINTERSUNIONSDIFF命令分别获取多个集合的交集、并集、差集

    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> SADD key1 a b c d e f g
    (integer) 7
    127.0.0.1:6379> SADD key2 c d e f g
    (integer) 5
    127.0.0.1:6379> SINTER key1 key2  # 交集
    1) "d"
    2) "f"
    3) "e"
    4) "c"
    5) "g"
    127.0.0.1:6379> SUNION key1 key2  # 并集
    1) "d"
    2) "g"
    3) "c"
    4) "e"
    5) "f"
    6) "b"
    7) "a"
    127.0.0.1:6379> SDIFF key1 key2  # 差集
    1) "b"
    2) "a"
    

集合的特性

  • 元素的唯一性:集合中的元素是唯一的,不会出现重复的元素

    127.0.0.1:6379> SADD myset1 csq1 csq2 csq3 csq3  # 添加4个元素 csq3添加两次
    (integer) 3
    127.0.0.1:6379> SMEMBERS myset1 # 发现只有三个元素 不会出现重复的元素
    1) "csq3"
    2) "csq2"
    3) "csq1"
    
  • 无序性:集合中的元素没有固定的顺序,每次获取的元素顺序可能不同

    应用场景:Redis集合常用于存储一些唯一性的元素,如用户标签、点赞用户列表、粉丝列表等。

哈希Hash

在Redis中,哈希(Hash)是一种键值对的数据结构,其中的键(Field)和值(Value)都是字符串类型的。

  1. 基本操作:

    • 设置字段值:使用HSET命令设置哈希中指定字段的值,使用HMSET命令设置哈希中多个字段的值

      127.0.0.1:6379> HSET myhash field1 csq1  # 设置 myhash field1的值为csq1
      (integer) 1
      127.0.0.1:6379> HMSET myhash field2 csq2 field3 csq3 # 设置myhash 多个字段多个值
      (integer) 2
      
    • 获取字段值:使用HGET命令获取哈希中指定字段的值,使用HMGET命令查询哈希中多个值

      127.0.0.1:6379> HGET myhash field1  # 查看myhash的field1中字段的值
      "csq1"
      127.0.0.1:6379> HMGET myhash field1 field2 field3 # 查看myhash中的多个字段的值
      1) "csq1"
      2) "csq2"
      3) "csq3"
      
    • 删除字段:使用HDEL命令删除哈希中的一个或多个字段

      127.0.0.1:6379> HMGET myhash field1 field2 field3 # 查看myhash field1 到 field3的值
      1) "csq1"
      2) "csq2"
      3) "csq3"
      127.0.0.1:6379> HDEL myhash field1 field2      # 删除field1字段和field2字段的值
      (integer) 2
      127.0.0.1:6379> HMGET myhash field1 field2 field3 # 查看myhash field1 到 field3的值
      1) (nil)
      2) (nil)
      3) "csq3"
      
    • 获取所有字段和值:使用HGETALL命令获取哈希中的所有字段和对应的值

      127.0.0.1:6379> HGETALL myhash 
      1) "field3"
      2) "csq3"
      
    • 获取所有字段:使用HKEYS命令获取哈希中的所有字段

      127.0.0.1:6379> HMSET field1 csq1 field2 zhw2
      127.0.0.1:6379> HGETALL myhash
      1) "field3"
      2) "csq3"
      3) "field1"
      4) "csq1"
      5) "field2"
      6) "zhw2"
      127.0.0.1:6379> HKEYS myhash # 获取myhash中的所有字段
      1) "field3"
      2) "field1"
      3) "field2"
      
    • 获取所有值:使用HVALS命令获取哈希中的所有值

      127.0.0.1:6379> HGETALL myhash
      1) "field3"
      2) "csq3"
      3) "field1"
      4) "csq1"
      5) "field2"
      6) "zhw2"
      127.0.0.1:6379> HVALS myhash # 获取myhash中所有字段的值
      1) "csq3"
      2) "csq1"
      3) "zhw2"
      
    • 获取字段数量:使用HLEN命令获取哈希中字段的数量

      127.0.0.1:6379> HGETALL myhash 
      1) "field3"
      2) "csq3"
      3) "field1"
      4) "csq1"
      5) "field2"
      6) "zhw2"
      127.0.0.1:6379> HLEN myhash  # 获取哈希中字段的数量
      (integer) 3 # 3个字段
      
    • 判断字段是否存在:使用HEXISTS命令判断指定字段是否存在于哈希中

      127.0.0.1:6379> HEXISTS myhash field4 # 判断myhash中的field4字段是否存在
      (integer) 0 # 返回0不存在
      127.0.0.1:6379> HEXISTS myhash field3 # 判断myhash中的field3字段是否存在
      (integer) 1 # 返回1存在
      

哈希的特性:

  • 灵活性:哈希适合存储和表示对象,可以将一个对象的各个属性存储为哈希的字段和值。

  • 查询效率高:哈希表内部使用散列(Hash)函数将字段映射到哈希表的槽位,通过槽位可以快速查找和访问字段的值,因此查询效率很高。

    应用场景:Redis的哈希类型常用于存储和表示对象,如用户信息、商品信息、文章信息等。通过哈希类型,可以方便地将一个对象的各个属性存储为字段和值,并可以通过字段名快速获取和修改对应的值。

有序集合Zset

在Redis中,有序集合(Sorted Set,简称ZSet)是一种有序的、不重复的数据结构。它类似于集合(Set),但每个元素都有一个与之关联的分数(score),通过分数可以对元素进行排序。

  1. 基本操作:

    • 添加元素:使用ZADD命令向有序集合中添加一个或多个元素,每个元素都有一个分数与之关联

      127.0.0.1:6379> ZADD myzset 1 csq1 4 csq4 3 csq3 2 csq2
      (integer) 4
      127.0.0.1:6379> ZRANGE myzset 0 -1
      1) "csq1"
      2) "csq2"
      3) "csq3"
      4) "csq4"
      
    • 删除元素:使用ZREM命令从有序集合中删除一个或多个元素

      127.0.0.1:6379> ZRANGE myzset 0 -1
      1) "csq1"
      2) "csq2"
      3) "csq3"
      4) "csq4"
      127.0.0.1:6379> ZREM myzset csq1
      (integer) 1
      127.0.0.1:6379> ZREM myzset csq2 csq3
      (integer) 2
      127.0.0.1:6379> ZRANGE myzset 0 -1
      1) "csq4"
      
    • 获取指定排名范围内的元素:使用ZRANGE命令获取有序集合中指定排名范围内的元素

      127.0.0.1:6379> ZRANGE myzset 0 -1
      1) "csq1"
      2) "csq2"
      3) "csq3"
      4) "csq4"
      
    • 获取元素的分数:使用ZSCORE命令获取有序集合中指定元素的分数

      127.0.0.1:6379> ZRANGE myzset 0 -1
      1) "csq4"
      127.0.0.1:6379> ZSCORE myzset csq4
      "4"
      
    • 增加元素的分数:使用ZINCRBY命令增加有序集合中指定元素的分数

      127.0.0.1:6379> FLUSHDB
      OK
      127.0.0.1:6379> zadd myzset 5 csq
      (integer) 1
      127.0.0.1:6379> ZINCRBY myzset +1 csq
      "6"
      127.0.0.1:6379> ZINCRBY myzset +500 csq
      "506"
      127.0.0.1:6379> ZINCRBY myzset +500 csq
      "1006"
      
    • 获取有序集合的元素数量:使用ZCARD命令获取有序集合中元素的数量

      127.0.0.1:6379> FLUSHDB
      OK
      127.0.0.1:6379> ZADD people 1000 school 500 square 4000 amusementpark
      (integer) 3
      127.0.0.1:6379> ZCARD people
      (integer) 3
      
    • 获取指定分数范围内的元素:使用ZRANGEBYSCORE命令获取有序集合中指定分数范围内的元素

      127.0.0.1:6379> FLUSHDB
      OK
      127.0.0.1:6379> ZADD money 5000 csq  5001 zhw  300 zzh  10000 teacher 
      (integer) 4
      127.0.0.1:6379> ZRANGEBYSCORE money 5000 10000 # 获取money在 5000 ~ 10000的人从低到高排序
      1) "csq"
      2) "zhw"
      3) "teacher"
      # 获取money在 5000 ~ 10000的人 并显示他们的钱数
      127.0.0.1:6379> ZRANGEBYSCORE money 5000 10000 withscores
      1) "csq"
      2) "5000"
      3) "zhw"
      4) "5001"
      5) "teacher"
      6) "10000"
      
      ########################
      # 从大到小排序
      127.0.0.1:6379> FLUSHDB
      OK
      127.0.0.1:6379> ZADD myset 1 csq 2 zhw 3 zzh 4 ppp 5 ddd
      (integer) 5
      127.0.0.1:6379> ZREVRANGE myset 0 -1
      1) "ddd"
      2) "ppp"
      3) "zzh"
      4) "zhw"
      5) "csq"
      
    • 获取指定区间的的元素:使用ZCOUNT获取指定区间的元素

      127.0.0.1:6379> ZADD scores 80 Alice 90 Bob 70 Charlie 85 David
      (integer) 4
      127.0.0.1:6379> ZRANGE scores 0 -1
      1) "Charlie"
      2) "Alice"
      3) "David"
      4) "Bob"
      127.0.0.1:6379> ZCOUNT scores 80 90
      (integer) 3
      

    有序集合的特性:

    • 元素的有序性:有序集合中的元素按照其分数进行排序,可以根据分数进行范围查询和排名查询。
    • 元素的唯一性:有序集合中的元素是唯一的,不会出现重复的元素。

应用场景:Redis的有序集合常用于需要按照某个权重或分数进行排序的场景,如排行榜、优先级队列、计数器等。

三种特殊数据类型

地理空间geospatial

在Redis中,地理空间(Geospatial)是一种用于存储地理位置和执行地理位置相关操作的数据结构。Redis通过使用Geohash算法和空间索引来实现地理空间功能。

基本操作

城市经纬度查询

  • 添加地理位置:使用GEOADD命令将一个或多个地理位置添加到有序集合中

    将给定的空间元素(经度,纬度,名字)添加到指定的键里面,这些数据将会以有序集合的形式保存在key

    注意:

    GEOADD可以记录的坐标有限,很接近两级的区域将无法被索引。

    有效的经度在-180到180之间

    有效的纬度在-85.05112878到85.05112878之间

    如果输入的经纬度不在有效度数之间的话,geoadd将会返回一个error

    127.0.0.1:6379> GEOADD china:city 112.851274 35.497553 jincheng
    (integer) 1
    127.0.0.1:6379> GEOADD china:city 116.405285 39.904989 beijing
    (integer) 1
    127.0.0.1:6379> GEOADD china:city 121.472644 31.231706 shanghai
    (integer) 1
    127.0.0.1:6379> GEOADD china:city 123.429096 41.796767 shenyang
    (integer) 1
    127.0.0.1:6379> GEOADD china:city 112.549248 37.857014 taiyuan
    (integer) 1
    
  • 获取地理位置:使用GEOPOS命令获取指定地理位置的经纬度

    127.0.0.1:6379> GEOPOS china:city taiyuan
    1) 1) "112.54924803972244263"
       2) "37.85701483724372451"
    
  • 计算距离:使用GEODIST命令计算两个地理位置之间的距离(直线距离)

    image-20230717200556352

    127.0.0.1:6379> GEODIST china:city jincheng taiyuan KM
    "263.8132"
    
  • 根据距离获取地理位置:使用GEORADIUS命令根据指定的中心点和半径获取在范围内的地理位置

    127.0.0.1:6379> GEORADIUS china:city 120 30 300 KM
    1) "shanghai"
    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 KM withcoord withdist 
    1) 1) "jincheng"
       2) "667.0200"
       3) 1) "112.85127550363540649"
          2) "35.49755190302494867"
    2) 1) "taiyuan"
       2) "904.9063"
       3) 1) "112.54924803972244263"
          2) "37.85701483724372451"
    
  • 根据经纬度获取地理位置:使用GEORADIUSBYMEMBER命令根据指定的地理位置和半径获取在范围内的地理位置

    127.0.0.1:6379> GEORADIUSBYMEMBER china:city jincheng 1000 KM 
    1) "jincheng"
    2) "taiyuan"
    3) "beijing"
    4) "shanghai"
    127.0.0.1:6379> GEORADIUSBYMEMBER china:city jincheng 800 KM withcoord withdist
    1) 1) "jincheng"
       2) "0.0000"
       3) 1) "112.85127550363540649"
          2) "35.49755190302494867"
    2) 1) "taiyuan"
       2) "263.8132"
       3) 1) "112.54924803972244263"
          2) "37.85701483724372451"
    3) 1) "beijing"
       2) "581.3722"
       3) 1) "116.40528291463851929"
          2) "39.9049884229125027"
    
  • Geohash是一种将地理位置编码为字符串的方法,它将二维的地理位置映射到一维的字符串上。

    127.0.0.1:6379> GEOHASH china:city jincheng taiyuan
      1) "ww21zypu1r0"
      2) "ww8p35ev5e0"
    

GEO底层的实现原理其实就是Zset,我们可以使用Zset命令来操作GEO

# 查询
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "shanghai"
2) "jincheng"
3) "taiyuan"
4) "beijing"
5) "shenyang"
# 删除
127.0.0.1:6379> ZREM china:city shenyang
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "shanghai"
2) "jincheng"
3) "taiyuan"
4) "beijing"

地理空间的特性:

  • 空间索引:Redis使用空间索引来加速地理位置的查询操作,可以高效地进行范围查询和附近地点搜索。
  • 距离计算:Redis可以计算两个地理位置之间的距离,支持不同的计算单位,如米(m)、千米(km)等。

基数统计Hyperloglog

在Redis中,HyperLogLog是一种基数统计算法,用于估计集合中不同元素的数量。HyperLogLog通过使用较小的固定内存空间来实现对非常大的集合进行基数估计,相比于传统的基数统计方法,它具有更低的内存消耗。

基本操作

  • PFADD命令:将一个或多个元素添加到HyperLogLog中

    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> PFADD mykey1 a b c d e f g
    (integer) 1
    
  • PFCOUNT命令:计算HyperLogLog中不同元素的数量

    127.0.0.1:6379> PFCOUNT mykey1
    (integer) 7
    
  • PFMERGE命令:将多个HyperLogLog合并成一个

    27.0.0.1:6379> PFADD mykey2 c d e f g h i j k
    (integer) 1
    127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2
    OK
    127.0.0.1:6379> PFCOUNT mykey3
    (integer) 11
    

应用场景:HyperLogLog广泛应用于需要对大规模集合进行基数统计的场景,如统计网站独立访客数、统计广告点击数等。

位图Bitmap

Redis的位图(Bitmaps)是一种特殊的数据结构,它以二进制位的形式存储数据。每个位可以表示某个元素的状态,比如是否存在、是否在线等。Redis的位图提供了一些位级别的操作,可以高效地处理位图数据

基础操作

设置位(SETBIT):将指定位置的位设置为指定的值(0或1)。可以用来记录某个元素的存在与否,比如记录用户的签到情况,每天签到的用户对应的位设置为1

127.0.0.1:6379> SETBIT sign 0 1
(integer) 0
127.0.0.1:6379> SETBIT sign 1 0
(integer) 0
127.0.0.1:6379> SETBIT sign 2 0
(integer) 0
127.0.0.1:6379> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379> SETBIT sign 4 0
(integer) 0
127.0.0.1:6379> SETBIT sign 5 1
(integer) 0
127.0.0.1:6379> SETBIT sign 6 0
(integer) 0

获取位(GETBIT):获取指定位置的位的值(0或1)。可以用来查询某个元素的状态,比如判断某个用户是否在线。

127.0.0.1:6379> GETBIT sign 6
(integer) 0
127.0.0.1:6379> GETBIT sign 5
(integer) 1
127.0.0.1:6379> GETBIT sign 4
(integer) 0

计数位(BITCOUNT):统计位图中值为1的位的数量。可以用来计算某个元素的出现次数,比如统计某个页面的访问量。

127.0.0.1:6379> BITCOUNT sign 
(integer) 3

位图在实际场景中有很多应用如:

  • 用户在线状态:可以使用位图记录用户的在线状态,每个位表示某个时间段内用户的在线情况。通过位操作,可以实时查询在线用户数、统计用户的在线时长等。
  • 用户活跃度统计:可以使用位图记录用户的活跃情况,每个位表示某一天用户的活跃与否。通过位操作,可以计算用户连续或不连续活跃天数,评估用户的活跃度。

事务

Redis支持事务,就是可以在一次请求中执行多个命令,Redis事务并不能保证所有命令都会执行成功,他执行结果取决于事务中的命令

Redis事务的使用步骤如下:

  1. 使用MULTI命令开启一个事务,此时客户端进入事务状态。

  2. 连续发送要执行的多个命令,这些命令会被加入到事务队列中,但不会立即执行。

  3. 使用EXEC命令执行事务,Redis会按照命令的先后顺序依次执行队列中的命令。

  4. 执行事务过程中,如果出现错误,Redis会继续执行后续的命令,直到所有命令都执行完毕。

  5. 执行完事务后,客户端退出事务状态。

Redis事务的特性和注意事项如下:

①:在发送EXEC命令之前,所有的命令都会被放入到一个队列中缓存起来不会立即执行

②:在收到EXEC命令之后事务开始执行,事务中任何一个命令执行失败其他命令依然会被执行,不会因为某个命令执行失败而导致其他命令不会被执行这样的情况发生

③:在事务执行的过程中,其他客户端提交的命令请求并不会插入到事务的执行命令序列中

Redis事务执行

image-20230718094543983

127.0.0.1:6379> FLUSHDB   # 清除当前数据库
OK
127.0.0.1:6379> MULTI     # 开启事务
OK
127.0.0.1:6379(TX)> SET myname chenshiren  
QUEUED   # 返回QUEUED 表示我们的命令已经被放入到了队列中
127.0.0.1:6379(TX)> SET age 18
QUEUED
127.0.0.1:6379(TX)> SET sex man
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) OK
3) OK
127.0.0.1:6379> MGET  myname age sex
1) "chenshiren"
2) "18"
3) "man"

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCR myname  # 自增
QUEUED
127.0.0.1:6379(TX)> INCR age     # 自增
QUEUED
127.0.0.1:6379(TX)> INCR sex     # 自增
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range  # 报错但不影响下一步执行
2) (integer) 19                  # 发生了改变
3) (error) ERR value is not an integer or out of range  # 报错
127.0.0.1:6379> MGET myname age sex 
1) "chenshiren"
2) "19"
3) "man"

image-20230718101616337

放弃事务

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET key aaaaa
QUEUED
127.0.0.1:6379(TX)> SET key1 bbbbb
QUEUED
127.0.0.1:6379(TX)> SET key2 cccc
QUEUED
127.0.0.1:6379(TX)> DISCARD  # 取消事务
OK
127.0.0.1:6379> MGET key key1 key2  # 事务队列中命令不会被执行
1) (nil)
2) (nil)
3) (nil)

redis乐观锁

乐观锁: 乐观锁是一种乐观的假设,认为并发访问的操作很少会冲突,因此在读取数据时不会进行加锁,只有在提交更新时才会检查是否发生冲突。乐观锁通常使用WATCH命令来实现。WATCH命令用于在事务执行期间监视一个或多个键的值,如果被监视的键在事务执行期间其他客户端修改,事务将被放弃执行,从而避免数据冲突

测试正常执行没有被修改的情况下


127.0.0.1:6379> get money
"1000"
127.0.0.1:6379> SET outmoeny 0
OK
127.0.0.1:6379> WATCH money outmoney
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECRBY money 20
QUEUED
127.0.0.1:6379(TX)> INCRBY outmoney 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 980
2) (integer) 20

测试被其他客户端修改的情况下

127.0.0.1:6379> FLUSHDB
OK
127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set outmoney 0
OK
127.0.0.1:6379> WATCH money outmoney
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECRBY money 100
QUEUED
127.0.0.1:6379(TX)> INCRBY outmoney 100
QUEUED
127.0.0.1:6379(TX)> exec  # 执行之前使用领一个线程修改了我们的money值,这个时候就会执行失败
(nil)

悲观锁: 悲观锁是一种悲观的假设,认为并发访问的操作会经常发生冲突,因此在读取数据时会进行加锁,保证在同一时间只有一个客户端可以对数据进行操作。

Redis配置文件详解(常用配置)

单位

image-20230718120124026

包含

image-20230718120706771

模块

image-20230718120817391

网络

bind 0.0.0.0       # 绑定的IP
protected-mode yes # 是否开启保护模式,默认为yes。开启保护模式后,只允许本地连接,不允许远程连接
port 6379          # 端口
tcp-backlog        # 设置TCP连接队列的长度,默认为511
timeout            # 客户端连接的超时时间,单位为秒,默认为0(表示不超时)
tcp-keepalive      # 是否开启TCP keepalive功能,默认为0

GENERAL(通用设置)

daemonize           # 是否以守护进程的方式运行Redis,默认为no
pidfile             # Redis进程的pid文件路径
loglevel            # 日志输出级别,默认为notice
logfile             # 日志文件路径
databases           # Redis数据库的数量,默认为16
always-show-logo    # 是否始终显示Redis的Logo,默认为no
set-proc-title      # 是否修改进程标题,默认为yes。如果设置为no,则Redis不会修改进程标题,进程名称将保持为执行时的名称。

proc-title-template # 修改进程标题的模板。通过该模板可以自定义进程标题的显示内容。
模板中使用的变量有:
{title}        # 进程名称,如果是父进程则为执行时的名称,如果是子进程则为子进程类型。
{listen-addr}  # 绑定地址,如果是TCP或TLS端口,则显示地址和端口号
{server-mode}  # 特殊模式,如"[sentinel]"或"[cluster]"。
{port}         # TCP端口号,如果没有则显示0。
{tls-port}# TLS端口号,如果没有则显示0。
{config-file}  # 使用的配置文件名称。

SNAPSHOTTING(快照)

save 3600 1 300 100 60 10000    # 每隔1小时,如果有至少1个key发生变化,就执行RDB持久化 
                                # 每隔5分钟,如果有至少100个key发生变化,就执行RDB持久化
                                # 每隔1分钟,如果有至少10000个key发生变化,就执行RDB持久化
stop-writes-on-bgsave-error yes # 持久化如果出错,是否还要继续工作
rdbcompression yes              # 是否压缩rdb文件
rdbchecksum yes                 # 保持rdb文件的时候,进行错误的检查校验
dir ./                          # rdb文件保存的目录

REPLICATION(主从复制)

replicaof 
# 指定主节点的IP地址和端口号。
replica-serve-stale-data <yes/no> 
# 设置从节点在与主节点断开连接后是否继续提供过期数据
replica-read-only <yes/no> 
# 设置从节点是否只读
replica-priority 100 
# 设置从节点的复制优先级。复制优先级用于主节点选举和故障转移过程中
# 用于确定从节点是否有资格成为新的主节点
# 优先级越高的从节点,越有可能被选举为新的主节点。

SECURITY (安全)

requirepass     # 密码设置

CLIENTS(客户端)

maxclients 10000     # 设置能连接上redis最大客户端的数量

MEMORY MANAGEMENT(内存管理)

maxmemory <bytes>            # redis配置最大的内存容量
maxmemory-policy noeviction  # 内存到达上限之后的处理策略
# 六种策略
# noeviction      永不过期,返回错误
# allkeys-lru     删除lru算法的key
# volatile-lru    只对设置了过期时间的key进行LRU(默认值)
# allkeys-random  随机删除
# volatile-random 随机删除即将过期的key
# volatile-ttl    删除即将过期的 

APPEND ONLY MODE(AOF配置)

appendonly no    # 默认不开启aof模式,默认是使用rdb方式持久化的,大部分情况下,rdb完全够用
appendfilename "appendonly.aof" # 持久化文件的名字
# appendfsync always            # 每个写命令都立即同步到磁盘,保证最高的数据安全性,但性能较差
appendfsync everysec            # 每秒执行一次sync 可能会丢失1S的数据
# appendfsync no                # 完全依赖操作系统的缓存机制,速度最快但数据安全性较低。

Redis持久化

Redis是内存数据库,如果没有持久化的话那么服务器重启或者断电,那么之前所有的数据都会丢失,这对一个数据库来说非常致命,持久化就可以解决这个问题

Redis提供了两种持久化方式:RDB(Redis Database)AOF(Append Only File)

RDB

Redis RDB(Redis Database)持久化是一种将Redis数据以二进制格式保存到磁盘上的持久化方式

触发持久化:

可以通过Redis配置文件中的save指令来设置触发RDB持久化的条件。save指令接受一个时间和写操作的次数作为参数,表示在指定的时间间隔内或在指定的写操作次数达到一定阈值时,触发RDB持久化。

例如,save 60 5表示在1分钟内,如果至少有5个键被修改,则触发RDB持久化。

RDB过程

image-20230719113118914

  • 当RDB持久化被触发时,Redis会fork出一个子进程,负责将数据写入到硬盘上的RDB文件中,而父进程则继续处理客户端请求

  • 在子进程执行期间,Redis会将数据库中的数据进行快照,然后将快照数据写入到临时RDB文件中

  • 当子进程完成写入操作后,Redis会用临时文件替换原来的RDB文件,完成持久化过程

  • RDB文件是以二进制格式保存的,可以通过加载RDB文件来恢复数据

  • RDB文件的保存位置由配置文件中的dbfilenamedir指令指定

实践

注意:rdb保存的文件是dump.rdb,可以在配置文件redis.conf里面修改

例如,save 60 5表示在1分钟内,如果至少有5个键被修改,则触发RDB持久化。

# 在redis.conf文件中添加如下内容,最好添加在SNAPSHOTTING(快照)下面
save 60 5

测试RDB持久化,先删除之前的RDB文件

[root@redis-server bin]# rm -rf dump.rdb
[root@redis-server bin]# ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis.conf  redis-sentinel  redis-server

连接redis-cli,设置5个键值

127.0.0.1:6379> set myname csq
OK
127.0.0.1:6379> set myname1 csq1
OK
127.0.0.1:6379> set myname2 csq2
OK
127.0.0.1:6379> set myname3 csq3
OK
127.0.0.1:6379> set myname4 csq4
OK
# 然后到这里,你可以重新开个线程 cd 到dump.rdb 存储的目录下,可以看到生成了一个新的RDB文件
[root@redis-server bin]# ls -l
总用量 21640
-rw-r--r--. 1 root root      161 719 15:43 dump.rdb  # 刚刚创建的从时间可以看出来
# xxd是一个可以查看2进制或16进制文件内容的Linux命令,可以看到RDB中的内容
[root@redis-server bin]# xxd dump.rdb 
0000000: 5245 4449 5330 3031 30fa 0972 6564 6973  REDIS0010..redis
0000010: 2d76 6572 0537 2e30 2e39 fa0a 7265 6469  -ver.7.0.9..redi
0000020: 732d 6269 7473 c040 fa05 6374 696d 65c2  s-bits.@..ctime.
0000030: ad96 b764 fa08 7573 6564 2d6d 656d c298  ...d..used-mem..
0000040: b70f 00fa 0861 6f66 2d62 6173 65c0 00fe  .....aof-base...
0000050: 00fb 0400 0007 6d79 6e61 6d65 3204 6373  ......myname2.cs
0000060: 7132 0006 6d79 6e61 6d65 0363 7371 0007  q2..myname.csq..
0000070: 6d79 6e61 6d65 3304 6373 7133 0007 6d79  myname3.csq3..my
0000080: 6e61 6d65 3104 6373 7131 ff2e d329 7b77  name1.csq1...){w
0000090: 169a 58                                  ..X

把redis关机,再重新连接redis,看看数据是否还在

127.0.0.1:6379> SHUTDOWN
not connected> quit
[root@redis-server bin]# ps -ef |grep redis
root      29631   1742  0 15:49 pts/0    00:00:00 grep --color=auto redis 
[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli -a 000000
127.0.0.1:6379> MGET myname myname1 myname2 myname3 myname4
1) "csq"
2) "csq1"
3) "csq2"
4) "csq3"
5) "csq4"
# 可以看到数据还在

也可以使用save命令手动触发快照

127.0.0.1:6379> SHUTDOWN
not connected> quit
[root@redis-server bin]# vim redis.conf         # 将之前设置的持久化删除
[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli -a 000000
127.0.0.1:6379> set age1 18
OK
127.0.0.1:6379> MSET age2 19 age3 20 age4 21
OK
127.0.0.1:6379> save
OK
# 
127.0.0.1:6379> exit
[root@redis-server bin]# ls -l
总用量 21640
-rw-r--r--. 1 root root      125 719 16:16 dump.rdb
# ...(省略其他文件)...
# 查看rdb文件
[root@redis-server bin]# xxd  dump.rdb 
0000000: 5245 4449 5330 3031 30fa 0972 6564 6973  REDIS0010..redis
0000010: 2d76 6572 0537 2e30 2e39 fa0a 7265 6469  -ver.7.0.9..redi
0000020: 732d 6269 7473 c040 fa05 6374 696d 65c2  s-bits.@..ctime.
0000030: db9b b764 fa08 7573 6564 2d6d 656d c238  ...d..used-mem.8
0000040: f60e 00fa 0861 6f66 2d62 6173 65c0 00fe  .....aof-base...
0000050: 00fb 0400 0004 6167 6534 c015 0004 6167  ......age4....ag
0000060: 6532 c013 0004 6167 6531 c012 0004 6167  e2....age1....ag
0000070: 6533 c014 ff49 6f6f 3dd0 8684 6d         e3...Ioo=...m

RDB触发机制

  1. save的规则满足的情况下,会自动触发rdb规则
  2. 执行flushall命令,也会触发rdb规则
  3. 退出redis,也会产生rdb文件

如何恢复rdb文件?

我们可以设置redis.conf配置文件中的 dir 参数来指定 RDB文件存储位置,默认就是在redis的启动目录下,可以自行修改,redis启动的时候就会自动检查dump.rdb 恢复其中的数据。

可以使用如下命令来查看当前RDB文件存储的位置

127.0.0.1:6379> config get dir
1) "dir"
2) "/usr/local/bin"

总结

save就像是快照一样,快照文件有个缺点就是如果服务器在快照之后宕机了,那么最后一次快照之后的所有修改的内容都会丢失,RDB更适合用来备份,我们可以使用crontab命令在凌晨的时候执行一次save命令,然后将快照文件备份到其他地方,这样就可以保证数据的安全

AOF

Redis AOF(Append-Only File)意思就是指追加文件,它的原理是在执行写命令的时候,不仅会将命令写入到内存中,还会将命令写入到一个追加的文件中,这个文件就是AOF,它会以日志的形式来记录每一个写操作,当Redis重启时,会重新执行AOF文件中的命令,以恢复数据库的内容。AOF文件的追加写入方式可以保证数据的顺序性和完整性。

AOF持久化的开启和配置

  • 在Redis配置文件中,可以通过设置appendonly参数来开启AOF持久化。默认情况下,AOF持久化是关闭的。

  • 可以设置appendfilename参数来指定AOF文件的名称,默认为appendonly.aof

  • 可以设置appenddirname参数来指定AOF目录的名称,默认为appendonlydir

    通过设置appendfsync参数来控制AOF文件同步到磁盘的策略。有三种选项:

    • always:每个写命令都立即同步到磁盘,保证最高的数据安全性,但性能较差。
    • everysec:每秒同步一次,性能和数据安全性的平衡选项,可能会丢失1S的数据。
    • no:完全依赖操作系统的缓存机制,速度最快但数据安全性较低。
(1)开启AOF
# 在redis.conf文件中开启
appendonly yes  

(2)重启redis
127.0.0.1:6379> SHUTDOWN
not connected> quit
[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli -a 000000
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> 

(3)查看是否生成了AOF目录和AOF文件
127.0.0.1:6379> exit
[root@redis-server bin]# ls |grep appen*
appendonlydir    
[root@redis-server bin]# cd appendonlydir/
[root@redis-server appendonlydir]# ls
appendonly.aof.1.base.rdb  appendonly.aof.1.incr.aof  appendonly.aof.manifest
# appendonly.aof.1.base. rdb作为基本文件
# appendonly.aof.1.incr.aof 作为增量文件的Aof
# 将appendonly.aof.manifest作为一个manifest文件,用于记录AOF文件的相关信息和状态
此时增量文件中是没有任何东西的,因为我们没有做出任何修改

(4)登录redis修改键值,退出来查看AOF增量文件
[root@redis-server bin]# redis-cli -a 000000
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set nameA csq
OK
127.0.0.1:6379> set nameB zhw
OK
127.0.0.1:6379> set nameC cccc
OK
127.0.0.1:6379> set nameD dddd
OK
127.0.0.1:6379> set nameE eeee
OK
127.0.0.1:6379> exit
[root@redis-server bin]# cat appendonlydir/appendonly.aof.1.incr.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$5
nameA
$3
csq
*3
$3
set
$5
nameB
$3
zhw
*3
$3
set
$5
nameC
$4
cccc
*3
$3
set
$5
nameD
$4
dddd
*3
$3
set
$5
nameE
$4
eeee
# 可以看到很多的参数,这个就是我们刚刚设置的值

AOF文件的恢复:

  • 当Redis服务器重启时,会根据AOF文件中的写命令恢复数据。
  • Redis会按照AOF文件中的顺序依次执行写命令,将数据恢复到内存中。
  • 恢复过程中如果遇到错误的命令或格式错误,Redis会停止恢复并报错,需要修复AOF文件后重新启动。

测试:假如有个人把你的AOF增量文件修改了,写入了一些乱码应该怎么修复?

image-20230719182544946

[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli -a 000000
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> quit
# 可以看到如果AOF增量文件被恶意修改是进不去redis的

修复

[root@redis-server bin]# redis-check-aof --fix appendonlydir/appendonly.aof.1.incr.aof 
Start checking Old-Style AOF
0x              10: Expected prefix '$', got: 'a'
AOF analyzed: filename=appendonlydir/appendonly.aof.1.incr.aof, size=223, ok_up_to=0, ok_up_to_line=4, diff=223
This will shrink the AOF appendonlydir/appendonly.aof.1.incr.aof from 223 bytes, with 223 bytes, to 0 bytes
Continue? [y/N]: y
Successfully truncated AOF appendonlydir/appendonly.aof.1.incr.aof

# 修复完毕后再次登录
[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-cli -a 000000
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> GET nameB
"zhw"

AOF重写

image-20230719184411675

由于AOF文件会不断增长,为了避免文件过大影响性能,Redis提供了AOF重写机制。

AOF重写是将内存中的数据重新生成一个新的AOF文件,只包含了当前数据库状态下的写命令。

AOF重写不会影响Redis服务器的正常运行,可以在后台进行。

Redis发布订阅

Redis发布订阅(Publish/Subscribe)是一种消息传递模式,它允许不同的组件(发布者和订阅者)在Redis中进行通信。发布者将消息发布到指定的频道,而订阅者可以选择订阅一个或多个频道来接收相应的消息。

image-20230719191748033

  • 发布者(Publisher):发布者是发送消息的角色。它使用PUBLISH命令将消息发布到指定的频道。

  • 频道(Channel):频道是消息的通道。发布者可以将消息发布到一个或多个频道中。频道的命名是字符串,订阅者可以根据频道名称来选择订阅。

  • 订阅者(Subscriber):订阅者是接收消息的角色。它使用SUBSCRIBE命令来订阅一个或多个频道,并通过监听频道来接收发布者发送的消息。

  • 消息(Message):消息是发布者发送的数据。它可以是任意类型的数据,如字符串等。

Redis发布订阅模式的使用流程如下

  1. 发布者使用PUBLISH命令将消息发布到指定的频道,如PUBLISH channel message
  2. 订阅者使用SUBSCRIBE命令来订阅一个或多个频道,如SUBSCRIBE channel1 channel2
  3. 订阅者通过监听频道来接收发布者发送的消息。当有新消息发布到已订阅的频道时,订阅者将收到相应的消息。
  4. 订阅者可以通过执行UNSUBSCRIBE命令来取消对指定频道的订阅,或执行UNSUBSCRIBE命令不带任何参数来取消对所有频道的订阅。

测试

发送端:

127.0.0.1:6379> PUBLISH CCTV <<喜羊羊>>        # 发布消息到指定频道
(integer) 1
127.0.0.1:6379> PUBLISH CCTV <<哆啦A梦>>       # 发布消息到指定频道
(integer) 1

订阅端:

[root@redis-server bin]# redis-cli  -a 000000 --raw   # 订阅一个频道
127.0.0.1:6379> SUBSCRIBE CCTV
subscribe
CCTV
1
message   # 消息
CCTV      # 来自哪个频道的消息
<<喜羊羊>> # 消息内容
message
CCTV
<<哆啦A梦>>
# 我们可以看到 接收端已经接收到了消息

但是发布订阅功能还有一些局限性

消息无法持久化Redis发布订阅模式下,消息是实时发送和接收的,并不会在Redis中进行持久化存储。这意味着如果订阅者在消息发布之前启动或重新连接,它将无法接收到之前发布的消息。这是因为Redis发布订阅模式主要用于实时消息传递,而不是消息的长期存储。

无法记录历史消息Redis发布订阅模式下,订阅者只能接收到它在订阅之后发布的消息,而无法获取订阅之前发布的消息。

消息队列Stream

Redis Stream是Redis 5.0版本中引入的一种高性能、持久化的消息队列数据结构。

Stream 数据结构:Stream是一个有序、不重复的消息队列,它由多个消息组成。每个消息都有一个唯一的ID,用于保证消息的顺序和去重。Stream通过一个键来进行标识和访问,可以将其看作是一个日志文件。

Stream的命令都是由X开头

消息:Stream中的消息是一个有序键值对,其中键是自动生成的唯一ID,值是消息的内容。每个消息都可以有自己的元数据,如时间戳、标签等。

XADD 命令将消息发布到Stream中,可以指定消息的ID、字段和值

127.0.0.1:6379> XADD csq * course nginx   # * 是不指定ID,系统给你设置ID
"1689808986732-0"
127.0.0.1:6379> XADD csq * course redis
"1689808993365-0"
127.0.0.1:6379> XADD csq * course mysql
"1689809006582-0"
127.0.0.1:6379> XADD csq 1-0 course nginx  # 注意ID的格式通常是一个整数-整数 第一个整数是时间戳第二个整数是序列号 ID不能相同
"1-0"
127.0.0.1:6379> XADD csq 2-0 course docker
"2-0"
127.0.0.1:6379> XADD csq 3-0 course mysql
"3-0"
127.0.0.1:6379> XADD csq 4-0 course redis
"4-0"

XLEN 查看stream中的消息数量

127.0.0.1:6379> XLEN csq
(integer) 3

XRANGE 获取指定范围内的消息

127.0.0.1:6379> XRANGE csq - +   # - + 代表获取csq的全部消息
1) 1) "1689808986732-0"
   2) 1) "course"
      2) "nginx"
2) 1) "1689808993365-0"
   2) 1) "course"
      2) "redis"
3) 1) "1689809006582-0"
   2) 1) "course"
      2) "mysql"

XDELXTRIM删除消息

127.0.0.1:6379> XDEL csq 1689808986732-0
(integer) 1
127.0.0.1:6379> XRANGE csq - +
1) 1) "1689808993365-0"
   2) 1) "course"
      2) "redis"
2) 1) "1689809006582-0"
   2) 1) "course"
      2) "mysql"

# 删除所有消息
127.0.0.1:6379> XTRIM csq MAXLEN 0
(integer) 2
127.0.0.1:6379> XRANGE csq - +
(empty array)    # 可以看到已经没消息了

XRED用来读取消息

# COUNT 表示一次读取几条消息
# BLOCK 表示如果没有消息就阻塞1000毫秒
# STREAMS 后面加上消息队列的名称
# 0 表示从头开始读取
127.0.0.1:6379> XREAD COUNT 2 BLOCK 1000 STREAMS csq 0
1) 1) "csq"
   2) 1) 1) "1-0"
         2) 1) "course"
            2) "nginx"
      2) 1) "2-0"
         2) 1) "course"
            2) "docker"
# 如果把0改成比我们消息队列ID还大的值
127.0.0.1:6379>  XREAD COUNT 2 BLOCK 1000 STREAMS csq 4  # 因为没有ID大于4的就会阻塞1秒
(nil)
(1.04s)
# 如果你想获取从现在开始 最新的消息可以将0改为$
# 将阻塞时常设置为10秒,再开启一个终端输入 XADD csq 5-0 course openstack
# XREAD 即可接收并输出这条消息
127.0.0.1:6379>  XREAD COUNT 2 BLOCK 10000 STREAMS csq $
1) 1) "csq"
   2) 1) 1) "5-0"
         2) 1) "course"
            2) "openstack"
(3.55s)

消费者组:多个消费者可以组成一个消费者组,共同消费Stream中的消息。在消费者组中,每个消费者都有一个独立的消费位置。当一个消费者消费了一条消息后,其他消费者不会再收到该消息。

消费者:消费者是指从Stream中接收消息的客户端。每个消费者都有一个唯一的ID,并可以加入一个或多个消费者组。

消费者组通过执行 XGROUP 命令来创建和管理。也可以通过XGROUP命令来添加消费者

127.0.0.1:6379> XGROUP create csq group1 0
OK
127.0.0.1:6379> XGROUP CREATECONSUMER csq group1 chenshiren
(integer) 1
127.0.0.1:6379> XGROUP CREATECONSUMER csq group1 chenshiren2
(integer) 1
127.0.0.1:6379> XGROUP CREATECONSUMER csq group1 chenshiren3
(integer) 1
127.0.0.1:6379> XINFO GROUPS csq
1)  1) "name"
    2) "group1"
    3) "consumers"
    4) (integer) 3  # 可以看到已经三个消费者了
    5) "pending"
    6) (integer) 0
    7) "last-delivered-id"
    8) "0-0"
    9) "entries-read"
   10) (nil)
   11) "lag"
   12) (integer) 5

XINFO查看消费者组的信息

127.0.0.1:6379> XINFO GROUPS csq
1)  1) "name"
    2) "group1"
    3) "consumers"
    4) (integer) 3
    5) "pending"
    6) (integer) 0
    7) "last-delivered-id"
    8) "0-0"
    9) "entries-read"
   10) (nil)
   11) "lag"
   12) (integer) 5

使用 XREADGROUP 命令的阻塞模式,消费者可以在没有新消息时等待,当有新消息到达时立即处理。

127.0.0.1:6379> XREADGROUP GROUP group1 chenshiren COUNT 3  BLOCK 3000 STREAMS csq >
1) 1) "csq"
   2) 1) 1) "1-0"
         2) 1) "course"
            2) "nginx"
      2) 1) "2-0"
         2) 1) "course"
            2) "docker"
      3) 1) "3-0"
         2) 1) "course"
            2) "mysql"
127.0.0.1:6379> XREADGROUP GROUP group1 chenshiren COUNT 5  BLOCK 3000 STREAMS csq >
1) 1) "csq"
   2) 1) 1) "4-0"
         2) 1) "course"
            2) "redis"
      2) 1) "5-0"
         2) 1) "course"
            2) "openstack"
127.0.0.1:6379> XREADGROUP GROUP group1 chenshiren COUNT 6  BLOCK 3000 STREAMS csq >
(nil)
(3.05s)

消息持久化:Redis Stream 支持将消息持久化到磁盘,以保证消息的可靠性。可以使用 Redis 的RDB或 AOF 来实现持久化

Redis主从复制

Redis 主从复制,它通过将一个 Redis 服务器(称为主服务器)的数据复制到一个或多个其他 Redis 服务器(称为从服务器)上,实现数据的备份、负载均衡和高可用性。

主服务器(Master):主服务器是被复制的源服务器,它负责接收写操作并将数据复制到从服务器。

从服务器(Slave):从服务器是复制主服务器的目标服务器,它接收来自主服务器的数据复制,并在需要时提供读服务

主从复制的原理

从服务器向主服务器发送SYNC命令,请求进行全量复制。

主服务器收到SYNC命令后,会执行以下操作:

  • 创建一个RDB快照,将当前的数据状态保存到磁盘上的RDB文件中。
  • 将RDB文件发送给从服务器,并在发送期间继续记录主服务器的写命令操作(写命令缓冲区)。

从服务器接收到RDB文件后,会将其加载到内存中,然后通过执行加载后的RDB文件,将自己的数据状态更新到与主服务器一致的状态。

主服务器将写命令缓冲区中的写命令发送给从服务器,从服务器执行这些写命令,保持与主服务器的数据同步。

主服务器会继续将新的写命令发送给从服务器,从服务器也会执行这些命令来保持同步

当从服务器与主服务器的连接断开后,从服务器会尝试重新连接主服务器,重新进行全量复制来恢复数据同步

主从复制的主要作用

数据备份:通过主从复制,将主服务器上的数据复制到从服务器上,实现了数据的备份。

读写分离:通过主从复制,可以将读操作分摊到多个从服务器上,从而实现读写分离。主服务器负责处理写操作,而从服务器负责处理读操作。

负载均衡:通过主从复制,可以将读操作分布到多个从服务器上,从而实现负载均衡。多个从服务器可以同时处理读请求,减轻主服务器的负载压力

故障恢复:当主服务器发生故障或网络断连时,从服务器可以自动切换为主服务器,实现故障恢复。

环境配置

主节点不需要配置任何参数,因为默认的配置就是主节点,只需要修改从节点就可以了

修改的方式有两种:

一种是通过命令行执行命令,另一种是修改配置文件

这里介绍修改配置文件的方法

第一步:复制redis.conf配置文件并修改

[root@redis-server bin]# ls
redis-6380.conf    redis.conf    

# 编写redis-6380.conf
daemonize yes
port 6380
pidfile /var/run/redis_6380.pid
logfile "6380.log"
dbfilename dump-6380.rdb
replicaof 127.0.0.1 6379  # 代表是 127.0.0.1 6379 这个库的从节点
# 编辑redis-6381.conf文件
[root@redis-server bin]# cp -rf redis-6380.conf  redis-6381.conf 
在底线命令行模式输入:1,$s/6380/6381/g 这样就可以将文本中所有的"6380"替换为"6381"

第二步:启动redis

[root@redis-server bin]# redis-server redis.conf 
[root@redis-server bin]# redis-server redis-6380.conf 
[root@redis-server bin]# redis-server redis-6381.conf 
# 然后打开3个终端 分别输入
[root@redis-server bin]# redis-cli -p 6379 
127.0.0.1:6379> 
[root@redis-server bin]# redis-cli  -p 6380
127.0.0.1:6380> 
[root@redis-server bin]# redis-cli  -p 6381
127.0.0.1:6381> 

第三步:连接成功后查看信息

127.0.0.1:6379> info replication
# Replication
role:master                                                 # 主服务器的信息
connected_slaves:2            # 已连接的从服务器有2个
slave0:ip=127.0.0.1,port=6381,state=online,offset=112,lag=1 # 从服务器的信息
slave1:ip=127.0.0.1,port=6380,state=online,offset=112,lag=1
master_failover_state:no-failover     # 没有进行故障转移                      
master_replid:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_replid2:1e57381e6da68eefb795bba09a485ca706676532
master_repl_offset:112
second_repl_offset:15
repl_backlog_active:1                                       # 复制相关信息
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:98

127.0.0.1:6380> info replication
# Replication
role:slave     # 从服务器
master_host:127.0.0.1
master_port:6379
master_link_status:up  # 连接正常
master_last_io_seconds_ago:6
master_sync_in_progress:0
slave_read_repl_offset:56
slave_repl_offset:56
slave_priority:100 # 从服务器的优先级是100
slave_read_only:1  # 服务器设置为只读模式
replica_announced:1
connected_slaves:0
master_failover_state:no-failover  # 没有进行故障转移
master_replid:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_replid2:1e57381e6da68eefb795bba09a485ca706676532
master_repl_offset:56
second_repl_offset:15
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:42


127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6379
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_read_repl_offset:84
slave_repl_offset:84
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_replid2:1e57381e6da68eefb795bba09a485ca706676532
master_repl_offset:84
second_repl_offset:15
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:70

第四步:测试

# 主机写
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3 k4 v4 k5 v5
OK
127.0.0.1:6380> MGET k1 k2 k3 k4 k5
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
127.0.0.1:6381> MGET k1 k2 k3 k4 k5
1) "v1"
2) "v2"
3) "v3"
4) "v4"
5) "v5"
# 看到了吗 从机是不可以写的,只可以读
127.0.0.1:6380> set k6 v6
(error) READONLY You can't write against a read only replica.

哨兵模式

Redis哨兵模式是一种用于实现高可用性的架构模式。它通过引入一组独立的Redis Sentinel哨兵节点来监控和管理Redis主从复制集群,以实现故障检测、自动故障转移和故障恢复等功能。

image-20230720102712428

哨兵模式的主要组件包括

  1. 主服务器(Master):负责处理写操作和响应客户端的读写请求。

  2. 从服务器(Slave):复制主服务器的数据,负责读操作,并在主服务器发生故障时接管主服务器的角色。

  3. 哨兵节点(Sentinel):监控主服务器和从服务器的状态,进行故障检测,并在主服务器发生故障时自动进行故障转移和故障恢复。

哨兵模式的工作流程如下

Sentinel节点通过向Redis实例发送PING命令来监测实例的存活状态。

如果主服务器或从服务器无法响应哨兵节点的PING命令,哨兵节点会将该实例标记为主观下线

当哨兵节点检测到主服务器下线后,它会请求其他哨兵节点对该下线主服务器进行确认。一旦大部分哨兵节点都确认主服务器已下线,该主服务器就会被标记为客观下线

哨兵节点会从当前可用的从服务器中选出一个成为新的主服务器,并将其他从服务器切换为新的主服务器的从服务器。

哨兵节点会更新客户端的配置,将新的主服务器信息通知给客户端,使客户端能够重新连接到新的主服务器。

当主服务器恢复后,哨兵节点会将其重新添加到集群中,作为从服务器,并将其重新同步到最新的数据状态。

如果哨兵节点发现主服务器的故障已经解决,它可以选择将主服务器切换回来,并将当前的主服务器切换为从服务器。

环境配置

第一步:配置主从复制

首先,需要将Redis实例配置为主从复制模式,确保主服务器和从服务器之间可以互相通信

第二步:配置哨兵节点

在哨兵节点上创建一个配置文件,例如sentinel.conf

[root@redis-server bin]# vim sentinel.conf
sentinel monitor master 127.0.0.1 6379 1
# sentinel monitor <master-name> <ip> <port> <quorum>
# quorum 表示只需要一个哨兵节点同意就可以进行故障转移了

第三步:启动哨兵节点

[root@redis-server bin]# redis-sentinel sentinel.conf

第四步:模拟主节点宕机情况

127.0.0.1:6379> SHUTDOWN
not connected> quit
[root@redis-server bin]# ps -ef |grep redis  # 没有6379的进程
root        354 104990  0 09:48 pts/2    00:00:00 redis-cli -p 6380
root      51687      1  5 09:28 ?        00:04:04 redis-server 127.0.0.1:6381
root      56052  47862  0 09:30 pts/4    00:00:00 redis-cli -p 6381
root     119734  92485  0 10:43 pts/6    00:00:00 redis-sentinel *:26379 [sentinel]
root     130902      1  0 09:48 ?        00:00:06 redis-server 127.0.0.1:6380

查看哨兵日志

image-20230720111822327

查看6380 6381

127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6381,state=online,offset=21907,lag=0
master_failover_state:no-failover
master_replid:e5ba5dbec58d509259234ab8a3c67060b59936ff
master_replid2:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_repl_offset:21907
second_repl_offset:14395
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:855
repl_backlog_histlen:21053

127.0.0.1:6381> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:146514
slave_repl_offset:146514
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:e5ba5dbec58d509259234ab8a3c67060b59936ff
master_replid2:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_repl_offset:146514
second_repl_offset:14395
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:15
repl_backlog_histlen:146500

恢复6379 查看是否恢复成主节点(其实看日志已经知道了曾经的主节点已经变为了从节点)

127.0.0.1:6379> info replication
# Replication
role:slave              # 变成了从节点
master_host:127.0.0.1
master_port:6380
master_link_status:up
master_last_io_seconds_ago:1
master_sync_in_progress:0
slave_read_repl_offset:166883
slave_repl_offset:166883
slave_priority:100
slave_read_only:1
replica_announced:1
connected_slaves:0
master_failover_state:no-failover
master_replid:e5ba5dbec58d509259234ab8a3c67060b59936ff
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:166883
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:164723
repl_backlog_histlen:2161

# 查看6380
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2   # 新增一个从节点
slave0:ip=127.0.0.1,port=6381,state=online,offset=173835,lag=0
slave1:ip=127.0.0.1,port=6379,state=online,offset=173835,lag=0
master_failover_state:no-failover
master_replid:e5ba5dbec58d509259234ab8a3c67060b59936ff
master_replid2:18a7cdac533e333da3e19f48d4684277e7e8a22f
master_repl_offset:173835
second_repl_offset:14395
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:855
repl_backlog_histlen:172981

配置信息

# sentinel.conf
port 26379  # 运行端口,默认为26379

dir /tmp    # 哨兵的工作目录

sentinel monitor <master-name> <ip> <port> <quorum>
# master-name 可以自己命名主节点名字
# ip  port 监控的节点IP 和 端口
# quorum 表示几个哨兵节点同意就可以进行故障转移了

sentinel auth-pass <master-name> <password>
# 当你redis实例开启了requirepass 授权密码,这样所有连接redis的客户端都需要密码
# 设置哨兵连接主从的密码,必须设置和主从一样的才行

# 指定多少毫秒之后,主节点没有答应哨兵sentinel此时哨兵主管会认为主节点下线,默认30秒
sentinel down-after-milliseconds <master-name> <milliseconds>
# milliseconds 单位是毫秒

# 这个配置指定了发生故障切换最多可以有多少个从节点同时对新master进行同步
sentinel parallel-syncs mymaster 1
# 该命令设置了并行同步数为1,这意味着在进行故障转移时
# 只允许一个从节点同时进行同步操作,其他从节点将被阻止进行同步

# 故障转移的超时时间 failover-timeout,默认三分钟
sentinel failover-timeout mymaster 180000 

Redis缓存穿透和雪崩概述和解决方法

Redis缓存穿透和雪崩是两种常见的缓存问题,它们都可能导致缓存系统的性能下降或崩溃。

缓存穿透: 缓存穿透指的是恶意或非法请求导致缓存中没有对应的数据,导致请求直接访问数据库或后端服务,从而增加了数据库或后端服务的压力。缓存穿透通常发生在以下情况下:

  • 请求的数据本来就不存在,例如请求一个不存在的ID。

  • 恶意请求,例如大量请求不存在的ID,以消耗资源或攻击系统。

缓解缓存穿透的方法包括:

  • 增加数据校验,如对请求参数进行合法性校验或使用布隆过滤器进行过滤,以减少无效请求

  • 对于确实不存在的数据,也可以在缓存中存储一个空值,避免频繁访问数据库

下图来自百度百科

image-20230720122719620

缓存击穿:Redis缓存击穿是指在高并发情况下,一个热门的缓存数据过期失效后,大量的并发请求同时访问后端数据库或服务,导致数据库或服务压力剧增,甚至造成系统崩溃。

缓存击穿问题发生的原因

  • 热点数据失效:当一个热门的缓存数据过期或被删除时,大量的并发请求无法从缓存中获取到数据,需要直接访问后端数据库或服务。

  • 并发请求高峰:在高并发请求的情况下,大量的请求同时访问后端数据库或服务,导致数据库或服务的压力剧增。

解决缓存击穿问题的方法

  • 热点数据永不过期:对于一些热点数据,可以设置其缓存过期时间为永不过期,或者设置一个较长的过期时间。这样可以确保热点数据一直存在于缓存中,避免缓存击穿问题。

  • 互斥锁:在获取缓存数据之前,使用互斥锁来保护临界区,使得只有一个线程能够从数据库或服务中获取数据,其他线程需要等待。这样可以避免大量并发请求同时访问后端,减轻压力。

缓存雪崩: 缓存雪崩是指在缓存中大量的数据同时失效或过期,导致大量的请求直接访问后端数据库或服务,造成数据库或服务的压力剧增,甚至造成系统崩溃。

缓存雪崩通常发生在以下情况下:

  • 缓存数据同时失效:当缓存中大量的数据同时失效或过期时,大量的请求无法从缓存中获取到数据,需要直接访问后端数据库或服务。
  • 缓存服务器某个节点宕机或断网

解决缓存雪崩问题的方法:

  • Redis高可用
    搭建Redis集群,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。(异地多活!)
  • 限流降级
    在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
  • 数据预热
    数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀 。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值