Redis(一)

一、redis介绍:

  • redi是一个C语言编写的NoSql的Key-Value数据库;
  • 它支持存储的value类型包括string(字符串)、Linkedlist(链表)、set(集合)、zset(sorted set有序集合)和hash(哈希类型)。新版本新增支持类型 BitMaps位图、hyperloglog超小内存唯一值计算、geo地图定位
  • 单个value容量可达到512M,主要受物理内存限制。
  • 数据加载在内存中,部分数据会异步flush持久化到磁盘,断电后数据不会丢失;50个并发每秒读写10万次(10万QPS,即query per second没秒内查询次数);
  • 提供丰富的功能,如 慢查询、发布订阅、lua脚本、pipeline、事务、高可用、分布式支持
  • 支持多种语言(java PHP python)

1、redis应用场景

  • 缓存:提高响应速度和并发能力
  • 计数:统计视频网站播放次数,单线程下速度快、也不会出错(string类型,incr、decr)
  • 消息队列系统:简单的消息中间件功能
  • 排行榜:游戏排行
  • 社交网络:粉丝数、关注数
  • 实时系统:

2、多路复用 和 线程模型

阻塞模型:阻塞就是当前任务等待也不能执行别的任务他。

非阻塞模型:就是在当前线程等待时可以去处理别的任务。

​ 使用非阻塞多路复用器模式处理客户端请求;redis根据不同的事件类型交给事件分配器分配,依据不同的事件处理器进行应答/处理和响应客户端。

  1. Redis 采用了 非阻塞I/O 多路复用机制(epoll)处理大量的客户端 Socket 请求。
  2. Redis 采用单线程模型可以避免了多线程之间的竞争(频繁的上下文切换),避免死锁造成的性能损耗。
  3. Redis的全部操作是基于内存的。因此 Redis 瓶颈可能是机器的内存或者网络带宽,而并非 CPU。

Redis —单线程

2.1 单线程概念

Redis是单线程的原因:

  • Redis 单线程指的是「接收客户端请求->解析请求 ->进行数据读写等操作->发送数据给客户端」这个过程是由一个线程(主线程)来完成的
2.2 Redis 6.0 之后为什么引入了多线程?
  • 在 Redis 6.0 版本之后,也采用了多个 I/O 线程来处理网络请求,这是因为随着网络硬件的性能提升,Redis 的性能瓶颈有时会出现在网络 I/O 的处理上。

  • Redis引入多线程来处理网络I/O,仍然使用单线程来执行Redis命令。

  • 注意:对于命令的执行,Redis 仍然使用单线程来处理,不要误解 Redis 有多线程同时执行命令。

3、不同value类型应用场景

String:存放对象的序列化信息,或者用作计数

hash:存放键对应不同属性信息,对于一个整体信息比较直观好管理并且节省空间,因为有可能key1需要1属性,key2不需要;或者频繁更新属性值。缺点不好控制失效时间。

list:列表有序,可以重复值特性;微博消息,更新的消息lpush放在队列最左边,lrang获取10条信息,然后在具体获取其中的微博内容。

set:无序,无重复;抽奖活动中已经中奖的排除可以使用spop。

名称类型数据存储选项查询类型附加功能
122113231232421

[]:

4、Redis和Memcached的区别

Memcached支支持简单的string类型,redis支持更丰富的类型。

Memcached不支持持久化,redis支持持久化。

三、数据结构和内部编码

四、redis发布订阅

基于消息做的一个发布与订阅,首先先订阅发布者,然后通过消息队列获取订阅的消息。(类似于微信公众号)实际运用很少

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XXHmfzvY-1688042677238)(D:\my_software\Typora\localpicture\image-20230531205720654.png)]

五、redis持久化

1、RDB二进制文件

某一时间点快照,把内存中的数据写入磁盘的临时文件,作为快照,恢复的时候把快照文件读进内存。

1.1 RDB优劣势
优势
  • 某一时间点,全量备份
  • 灾备简单,可以远程传输
  • 子进程备份的时候,主进程不会有任何io操作(不会有写入修改或删除),保证备份数据的的完整性
  • 相对AOF来说,当有更大文件的时候可以快速重启恢复
劣势
  • 发生故障是,有可能会丢失最后一次的备份数据

  • 子进程所占用的内存比会和父进程一模一样,如会造成CPU负担

  • 由于定时全量备份是重量级操作,所以对于实时备份,就无法处理了。

触发生成RDB存储的三种方式:

  • save(同步命令,会造成阻塞):文件策略是将新生成的RDB文件替换老的文件
  • bgsave(异步,默认):创建一个fork线程去处理生成RDB文件,文件策略和save一样
  • 自动生成RDM(不使用):配置间隔时间内有改变就触发生成dump.rdb文件
命令savebgsave
IO类型同步异步
阻塞非阻塞
优点不消耗额外内存不占用客户端命令
缺点阻塞客户端命令需要fork消耗内存
配置redis.conf

修改 /usr/local/redis/redis.conf,Redis核心配置文件,可以设置不同时间保存不同明明的rdb文件,以方便恢复数据

stop-writes-on-bgsave-error yes    如果bgsave出现错误时停止写操作,no:可能造成数据不一致
rdbcomperssion   yes   		保存RDB文件使用压缩格式
rdbchecksum      yes		采用校验方式
save 300 10					设置更新10次缓存数据,在300秒后备份到RDB文件中
dir /usr/local/redis/working 		RDB文件保存路径

耗时、耗性能 ,所有的数据dump到硬盘,fork会消耗内存、大数据量对IO性能也是消耗,中间宕机会造成数据丢失情况。

2、AOF二进制文件

将redis写操作命令以实时日志形式追加到AOF文件中。

2.1、 AOF特点
  • 以日志的形式来记录用户请求的写操作。读操作不会记录,因为写操作才会存存储。

  • 文件以追加的形式而不是修改的形式。

  • redis的aof恢复其实就是把追加的文件从开始到结尾读取执行写操作。

    2.2、 优势
  • AOF更加耐用,可以以秒级别为单位备份,如果发生问题,也只会丢失最后一秒的数据,大大增加了可靠性和数据完整性。所以AOF可一次,使用fsync操作。

  • 以log日志形式追加,如果磁盘满了,会执行 redis-check-aof 工具

  • 当数据太大的时候,redis可以在后台自动重写aof。当redis继续把日志追加到老的文件中去时,重写也是非常安全的,不会影响客户端作。

  • AOF 日志包含的所有写操作,会更加便于redis的解析恢复。

    2.3、 劣势
  • 相同的数据,同一份数据,AOF比RDB大

  • 针对不同的同步机制,AOF会比RDB慢,因为AOF每秒都会备份做写操作,这样相对与RDB来说就略低。 每秒备份fsync没毛病,但是的每次写入就做一次备份fsync的话,那么redis的性能就会下降。

  • AOF发生过bug,就是数据恢复的时候数据不完整,这样显得AOF会比较脆弱,容易出现bug,因为AOF没有RDB那么简单,但是呢为
    的产生,AOF就不会根据旧的指令去重构,而是根据当时缓存中存在的数据指令去做重构,这样就更加健壮和可靠了。

    appendonly no # AOF 默认关闭,yes可以开启
    appendfilename "appendonly.aof" # AOF 的文件名
    
    # no:不同步
    # everysec:每秒备份,推荐使用
    # always:每次操作都会备份,安全并且数据完整,但是慢性能差
    appendfsync everysec
    
    no-appendfsync-on-rewrite no 	#重写的时候是否要同步,no可以保证数据安全
    
    # 重写机制:避免文件越来越大,自动优化压缩指令,会fork一个新的进程去完成重写动作,新进程里的内存数据会被重写,此时
    # 当前AOF文件的大小是上次AOF大小的100% 并且文件体积达到64m,满足两者则触发重写
    auto-aof-rewrite-percentage 100
    auto-aof-rewrite-min-size 64mb
    
2.3、AOF三种策略:
  • always:写命令每条命令都刷新到缓冲区,都写入硬盘
  • everysec(默认):写命令刷新到缓冲区,每秒定时写入到硬盘
  • no:写命令刷新到缓存,根据操作系统调度写入硬盘
命令alwayseverysecno
优点不丢失数据每秒一次刷新到硬盘不用管理
缺点IO开销比较大丢失一秒数据管控不了

AOF重写:
当AOF文件由于业务量而增大而增大,造成恢复很慢、写入速度影响,进行AOF重写,去掉一些键值的中间值留下最终值、过期、删除等,这样可以加快恢复速度、减少硬盘存储量。使用后台线程执行。

3、 AOF与RDB对比

命令RDBAOF
启动优先级
体积
恢复速度
数据安全性丢失数据根据策略决定,一般是eversec丢一秒数据
  • AOF的配置
    到底采用RDB还是AOF呢?
  1. 如果你能接受一段时间的缓存丢失,那么可以使用RDB
  2. 如果你对实时性的数据比较care,那么就用AOF

六、主从复制

由于单个节点的redis并发能力大概5/6万,使用主从复制横向扩展结点提高并发能力,提供副本保证高可用,扩展读性能。

/usr/local/redis/redis.conf			Redis核心配置文件位置,密码配置root,端口6379
/etc/init.d/redis_init_script		Redis启动脚本位置

修改 /usr/local/redis/redis.conf文件

replicaof 192.168.220.3 6379 #设置master节点ip和端口
masterauth root 	#设置访问redis密码
replica-read-only yes #默认就是从节点只读模式

查询状态

[root@root ~]# redis-cli 	#链接redis客户端
127.0.0.1:6379> auth root	#输入密码
OK
127.0.0.1:6379> info replication #查询当前主机状态
# Replication
role:master 		#当前节点角色 master主机,slave从节点	
connected_slaves:1  #从节点数量
slave0:ip=192.168.220.31,port=6379,state=online,offset=42,lag=0 #当前从节点信息
master_replid:ed2215ee72cd7f5a52087f1bdca62ce48b9f6a1d
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:42
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:42

开启主从模式,slave会全量同步master的RDB文件到磁盘,然后读取到内存;使用旧数据同步,保证master写操作slave读操作不影响;

slave只能读取,master可读可写;

默认master挂了不会自动选举,恢复后将数据继续同步到slave节点。

1、slaveof 命令

在从节点执行slaveof 主节点id 端口,异步执行;
主节点写,从节点读保持主从数据一致;
主节点通过bgsave触发RDB类型同步数据到从节点,从节点会清除自己独有数据和主节点完全一致数据。
无需重启,不便于管理。
使用命令slaveof no one可以解除自己的主节点关系

2、全量复制和部分复制

在这里插入图片描述

全量复制需要消耗大量的cpu、io、内存、RDB网络传输时间、从节点加载RDB时间;部分复制就是先全量复制然后对比1M缓存区的偏移量,在范围内直接传输偏移量,超过进行全量同步操作。

3、读写分离

主写从读,生产情况下度多写少;可能会出现网络延迟、从节点阻塞数据不一致、读到过期数据(3.2版本解决,从节点不能清除过期数据)、从节点故障

七、Redis Sentinel 哨兵模式

主从集群中出现master挂了,slave选取一个master节点,然后其他从节点设置新的主节点等操作,这些都需要手动完成;sentinel就是解决这一问题,提供监控、通知客户端、故障转移。

因为master写,slave只读,所以必须重新选举,并且重新选举后master恢复后成为slave。

客户端通过sentinel访问redis,不用管谁是master、slave;当master被多个sentinel监控有问题时,会从多个slave中选取一个master,然后其他slave slaveof这个master,之前挂了的master重启后为slave。

[root@root redis]# cp /home/xiao/software/redis-6.0.6/sentinel.conf  /usr/local/redis/
[root@root redis]# redis-sentinel sentinel.conf #后台启动哨兵
[root@root redis]# ps -ef|grep redis
root       1825   1781  0 19:16 pts/0    00:00:00 redis-cli
root       3242      1  0 20:51 ?        00:00:02 /usr/local/bin/redis-server 0.0.0.0:6379
root       3624      1  0 21:27 ?        00:00:00 redis-sentinel *:26379 [sentinel]
root       3630   2707  0 21:27 pts/1    00:00:00 grep --color=auto redis
[root@root redis]#scp sentinel.conf root@192.168.220.31:/usr/local/redis/

home/xiao/software/redis-6.0.6/sentinel.conf 哨兵文件配置

port 26379 #端口
dir "/usr/local/redis/sentinel" #工作路径
daemonize yes	# 守护进程模式,后台运行
logfile "/usr/local/redis/sentinel/sentinel.log"	# 指明日志文件名
#哨兵监控的master,主从配置一样,在进行主从切换时6379会变成当前的master端口,2表示2个哨兵标识为挂掉后重新选举
sentinel monitor mymaster 192.168.220.3 6379 2
# master或slave多长时间(默认30秒)不能使用后标记为s_down状态。
sentinel down-after-milliseconds mymaster 5000
#若sentinel在该配置值内未能完成failover操作(即故障时master/slave自动切换),则认为本次failover失败。
sentinel failover-timeout mymaster 18000
#设置master和slaves验证密码
sentinel auth-pass mymaster root
#哨兵程序自动添加的部分
# Generated by CONFIG REWRITE
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 1
###指明了当前群集的从库的ip和端口,在主从切换时该值会改变
sentinel known-slave mymaster 192.168.137.40 6380
###除了当前的哨兵还有哪些监控的哨兵
sentinel known-sentinel mymaster 192.168.137.40 26379 7a88891a6147e202a53601ca16a3d438e9d55c9d
sentinel current-epoch 1
查看相关信息
# 查看mymaster下的master节点信息
sentinel master mymaster
# 查看mymaster下的slaves节点信息
sentinel slaves mymaster
# 查看imooc-master下的哨兵节点信息
sentinel sentinels mymaster

1、 哨兵整合spring boot,在application.yml中配置

spring:
  redis:
    password: root
    database: 1
    sentinel:
      master: mymaster #监控的master名字
      nodes: 192.168.220.3:26379,192.168.220.31:26379 #sentinel监控的所有节点,26379为哨兵线程端口

按如上配置即可有spring控制读写redis切换节点,由sentinel控制节点宕机后选举动作。

八、集群

​ 前面我们一起学习了主从复制以及哨兵,他们可以提高读的并发,但是单个master容量有限,数据达到一定程度会有瓶颈,这个时候可以通过水平扩展为多master多slave集群。

​ redis-cluster:他可以支撑多个master-slave,支持海量数据,实现高可用与高并发。
​ 哨兵模式其实也是一种集群,他能够提高读请求的并发,但是容错方面可能会有一些问题,比如master同步数据给slave的时候,这其实是异步复制吧,这个时候如果master挂了,那么slave上的数据就没有master新,数据同步需要时间的,1-2秒的数据会丢失。master恢复并转换成slave后,新数据则丢失。

特点
  1. 每个节点知道彼此之间的关系,也会知道自己的角色,当然他们也会知道自己存在与一个集群环境中,他们彼此之间可以交互和通信(ping/ pong)。那么这些关系都会保存到某个配置文件中(nodes-6379.conf),每个节点都有,这个我们在搭建的时候会做配置的。

  2. 客户端要和集群建立连接的话,只需要和其中一个建立关系就行。

  3. 某个节点挂了,也是通过超过半数的节点来进行的检测,客观下线后主从切换,和我们之前在哨兵模式中提到的是一个道理。

  4. Redis中存在很多的插槽,又可以称之为槽节点,用于存储数据,这个先不管,后面再说。

集群容错

构建Redis集群,需要至少3个节点作为master,以此组成一个高可用的集群,此外每个master都需要配备一个slave,所以整个集群需要6个节点,这也是最经典redis集群模式,称作三主三从,容错性更佳。所以在搭建的时候需要有6台虚拟机。可以通过克隆去构建,使用单实例的Redis 去克隆即可,集群也可以在单服务器构建,称之为伪集群,但是生产环境肯定是真的,所以建议用6台。克隆后务必关闭Redis。

1、集群环境配置

修改 /usr/local/redis/redis.conf 文件配置

# 开启集群模式
cluster-enabled yes
# 每一个节点需要有一个配置文件,需要6份。每个节点处于集群的角色都需要告知其他所有节点,彼此知道,这个文件用于存储集群角色状态关系信息
cluster-config-file nodes-6379.conf
# 超时时间,超时则认为master宕机,随后主备切换
cluster-node-timeout 5000
# 开启AOF
appendonly yes
[root@root xiao]# /etc/init.d/redis_init_script stop
[root@root xiao]# /etc/init.d/redis_init_script start
[root@root xiao]# ps -ef|grep redis
root       2824      1  0 19:48 ?        00:00:00 /usr/local/bin/redis-server 0.0.0.0:6379 [cluster]
root       2838   2330  0 19:48 pts/0    00:00:00 grep --color=auto redis
#如下命令创建三主三从集群,cluster-replicas表示master与slave映射比值
[root@root ~]# redis-cli -a root  --cluster create 1192.168.217.128:8001 192.168.217.128:8002 192.168.217.128:8003 192.168.217.128:8004 192.168.217.128:8005 192.168.217.128:8006  --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.168.217.128:8005 to 192.168.217.128:8001
Adding replica 192.168.217.128:8006 to 192.168.217.128:8002
Adding replica 192.168.217.128:8004 to 192.168.217.128:8003
M: 02d47d69650337ec4a967f5311718939c65d61ee 192.168.217.128:8001
   slots:[0-5460] (5461 slots) master
M: 736fe6711ab1c1abfaace923fa553661bf956c37 192.168.217.128:8002
   slots:[5461-10922] (5462 slots) master
M: 160224afce6c868c653d8e26e0cc5bdaf8da17be 192.168.217.128:8003
   slots:[10923-16383] (5461 slots) master
S: 1e10e6ac6562918ee95480feb7a48e4679c3db62 192.168.217.128:8004
   replicates 160224afce6c868c653d8e26e0cc5bdaf8da17be
S: 7952c769a0adb08753554e8767fdd415ed7a4e43 192.168.217.128:8005
   replicates 02d47d69650337ec4a967f5311718939c65d61ee
S: 0f3e37ec085d26448898129af9388f1a74a2c19e 192.168.217.128:8006
   replicates 736fe6711ab1c1abfaace923fa553661bf956c37
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
....
>>> Performing Cluster Check (using node 192.168.217.128:8001)
M: 02d47d69650337ec4a967f5311718939c65d61ee 192.168.217.128:8001
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
M: 160224afce6c868c653d8e26e0cc5bdaf8da17be 192.168.217.128:8003
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
S: 0f3e37ec085d26448898129af9388f1a74a2c19e 192.168.217.128:8006
   slots: (0 slots) slave
   replicates 736fe6711ab1c1abfaace923fa553661bf956c37
S: 1e10e6ac6562918ee95480feb7a48e4679c3db62 192.168.217.128:8004
   slots: (0 slots) slave
   replicates 160224afce6c868c653d8e26e0cc5bdaf8da17be
M: 736fe6711ab1c1abfaace923fa553661bf956c37 192.168.217.128:8002
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
S: 7952c769a0adb08753554e8767fdd415ed7a4e43 192.168.217.128:8005
   slots: (0 slots) slave
   replicates 02d47d69650337ec4a967f5311718939c65d61ee
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

2、slot槽节点

  • 总共有16384个槽节点,数据都存储于槽节点中,槽节点平均分布于各个master节点,不会存储在slave节点。
  • 槽节点按照顺序平均分配不同频段到各个master
  • 数据存储与查询通过 hash(key)%16384 到不同master的槽节点上。

3、

00:0c:29:b6:26:84  00:0c:29:33:8b:e1

vim /etc/udev/rules.d/70-persistent-ipoib.rules

vim /etc/sysconfig/network-scripts/ifcfg-ens33

service network restart
/etc/init.d/redis_init_script stop
/etc/init.d/redis_init_script start
ps -ef|grep redis

九、常见问题

1、redis缓存过期机制

设置了expire过期时间的key缓存过期了,但是服务器的内存还是会被占用,这是因为redis所基于的两种删除策略
redis有两种策略:

  1. (主动)定时删除
    定时随机的检查过期的key,如果过期则清理删除。(每秒检查次数在redis.conf中的hz配置)

  2. (被动)惰性删除
    当客户端请求一个已经过期的key的时候,那么redis会检查这个key是否过期,如果过期了,则删除,然后返回一个nil。这种策略
    友好,不会有太多的损耗,但是内存占用会比较高。

所以,虽然key过期了,但是只要没有被redis清理,那么其实内存还是会被占用着的。

2、 内存淘汰管理机制

那么如果内存被Redis缓存占用慢了咋办?内存占满了,可以使用硬盘,来保存,但是没意义,因为硬盘没有内存快,会影响redis性能。
所以,当内存占用满了以后,redis提供了一套缓存淘汰机制:MEMORY MANAGEMENT

maxmemory :当内存已使用率到达,则开始清理缓存

  • noeviction:旧缓存永不过期,新缓存设置不了,返回错误(默认)
  • allkeys-lru:清除最少用的旧缓存,然后保存新的缓存(推荐使用)
  • allkeys-random:在所有的缓存中随机删除(不推荐)
  • volatile-lru:在那些设置了expire过期时间的缓存中,清除最少用的旧缓存,然后保存新的缓存
  • volatile-random:在那些设置了expire过期时间的缓存中,随机删除缓存
  • volatile-ttl:在那些设置了expire过期时间的缓存中,删除即将过期的

3、缓存穿透

缓存和数据库都不存在的数据

由于业务自身问题、恶意攻击、爬虫等,绕过缓存直接访问数据库,会造成数据库非常大的压力。

解决方案就是将key和value=空设置到缓存,并设置一个过期时间,这样就不会直接访问数据库了。

4、布隆过滤器

使用二进制存储形式保存,设置哪些请求可以访问

5、缓存击穿

由于缓存过期失效,导致请求到达数据库。

6、缓存雪崩

同一时刻大量的key失效或者redis缓存挂了,导致大量查询访问数据库。

  • 永不过期
  • 错开失效时间
  • 多层缓存

十、redis和memcached对比:

1、memcached只支持简单的字符串类型,redis支持多种复杂类型value;
2、memcached和redis都是将数据存在内存中。
3、memcached掉电后数据丢失,redis支持异步flush到磁盘,掉电后可以保存部分数据。
4、支持的value大小不一致,redis最大可达到1G,memcached只有1M。
5、memcached不支持主从同步,redis支持。
6、memcached不支持分片,redis支持。

redis官方之事务
redis快速入门
Redis
Redis内存模型

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值