avatar

Redis进阶

Redis发布订阅

简介

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。
Redis窖户端可以订阅任意数量的频道。

下图展示了频道channe11 ,以及订阅这个频道的三个客户端 一client2 、client5 和client1之间的关系

当有新消息通过PUBLISH命令发送给频道channel1 时,这个消息就会被发送始订阅它的三个客户端:

配置订阅和发布

命令

订阅频道

SUBSCRIBE channel [channe1 …] :订阅给定的一个或多个频道的信息
PSUBSCRIBE pattern [pattern …] :订阅-一个或多个符合给定模式的频道。

发布频道:

PUBLISH channe1 message :将信息发送到指定的频道。

退订频道:

UNSUBSCRIBE [channel [channel …]] :指退订给定的频道。
PUNSUBSCRIBE [pattern [pattern …]]: 退订所有给定模式的频道。

应用场景

这一功能最明显的用法就是构建实时消息系统,比如普通的即时聊天,群聊等功能
1、在一个博客网站中。有100个粉丝订阅了你,当你发布新文章。就可以推送消息给粉丝们。
2、微信公众号模式
微博,每个用户的粉丝都是该用户的订阅者,当用户发完微博 ,所有粉丝都将收 到他的动态;
新闻,资讯站点通常有多个频道.每个频道就是一个主题,用户可以通过主题来做订阅(如RSS) ,这样当新闻发布时,订阅者可以获得更新

简单的应用场量的话,以门户网站为例当编辑更新了某推荐板块的内容后:

1、CMS发布清除缓存的消息到channel (推送者推送消息)
2、门户网站的缓存系统通过chanel收到清除缓存的消息(订阅者收到消息) ,更新了推荐板块的缓存
3、还可以做集中配置中心管理,当配置信息发生更改后, 订阅配置信息的节点都可以收到通知消息

Redis多数据库

Redis下,数据库是由一个整数索引标识,而不是由一个数据库名称。默认情况下,一个客户端连接到数据库0。

redis配置文件中下面的参数来控制数据库总数;

1
database 16 //从0开始

select数据库 //数据库的切换

1
select index

移动数据(将当前key移动另个库)

1
move key名称 数掘库

数据库清空;

1
2
flushdb :清除当前数据库的所有key
flushall :清除整个Redis的数据库所有key

Redis事务

Redis事务可以一次执行多个命令,( 按顺序地串行化执行,执行中不会被其它命令插入,不许加塞)

简介

Redis事务可以一次执行多个命令(允许在-一次单独的步骤中执行一组命令) ,并且带有以下两个重要的保证:

批量操作在发送EXEC命令前被放入队列缓存。
收到EXEC命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

1、Redis会将一个事务中的所有命令序列化,然后按顺序执行
2、执行中不会被其它命令插入,不许出现加赛行为

命令

DISCARD
:取消事务,放弃执行事务块内的所有命令。
EXEC
:执行所有事务块内的命令。
MULTI
:标记一个事务决的开始。
UNWATCH
:取消WATCH 命令对所有key的监视。
WATCH key [key ..]
:监视一个(或多个) key, 如果在事务执行之前这个(或这些) key被其他命令所改动,那么事务将被打断。

一个事务从开始到执行会经历以下三个阶段:
开始事务。
命令入队。
执行事务。

示例1 MULTI EXEC

转账功能,A向B转账50元

1、输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行
2、直到输入Exec后,Redis会将之前的命令队列中的命令依次执行

示例2 DISCARD 放弃队列运行

1、输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行
2、直到输入Exec后, Redis会将之前的命令队列中的命令依次执行。
3、命令队列的过程中可以通过discard来放弃队列运行

示例3事务的错误处理

事务的错误处理:
如果执行的某个命令报出了错误,则只有报错的命令不会被执行,而其它的命令都会执行,不会回滚。

示例4事务的错误处理

事务的错误处理:
队列中的某个命令出现了报告错误,执行时整个的所有队列都会被取消。

示例5事务的WATCH

WATCH key [key …]
:监视一个(或多个) key , 如果在事务执行之前这个(或这些) key被其他命令所改动,那么事务将被打断。

需求:某一帐户在一事务内进行操作,在提交事务前,另一个进程对该帐户进行操作。

应用场景

一组命令必须同时都执行,或者都不执行。
我们想要保证一组命令 在执行的过程之中不被其它命令插入。

Redis 数据淘汰策略 redis.conf

Reds官方给的警告,当内存不足时,Redis会根据配置的缓存策略淘汰部分Keys,以保证写入成功.当无淘汰策略时或没有找到适合淘汰的Key时,Redis直接返回out of memory错误。

最大缓存配置

在redis中,允许用户设置最大使用内存大小
maxmemory 512G

redis提供6种数据淘汰策略:

  • volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  • volatile-lfu:从已设置过期的Keys中,删除一段时间内使用次数最少使用的
  • volatile-ttl:从已设置过期时间的数据集中挑选最近将要过期的数据淘汰
  • volatile-random:从已设置过期时间的数据集中随机选择数据淘汰
  • allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
  • allkeys-lfu:从所有Keys中,删除一段时间内使用次数最少使用的
  • allkeys-random:从数据集中随机选择数据淘汰
  • no-enviction (驱逐):禁止驱逐数据(不采用任何淘汰策略。默认即为此配置),针对写
    操作,返回错误信息

建议:了解了Redis的淘汰策略之后,在平时使用时应尽量主动设置/更新key的expire时间,
主动剔除不活跃的旧数据,有助于提升查询性能

Reids 持久化

简介

数据存放于:
内存:高效、断电(关机)内存数据会丢失
硬盘:读写速度慢于内存,断电数侧不会丢失

RDB

RDB: 是redis的默认持久化机制。
RDB相当于照快照,保存的是一种状态。
几十G数据 一》几KB快照
快照是默认的持久化方式。这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump. rdb.

优点:
快照保存数据极快,还原数据极快
适用于灾难备份

缺点:小内存机器不适合使用。RDB机制符合要求就会使用

快照条件

AOF

由于快照方式是在一定间隔时间做一次的, 所以如果redis意外down掉的话,就会丢失最
后一次快照后的所有修改。如果应用要求不能丢失任何修改的话,可以采用aof 持久化方式。

Append-only flie:aof 比快照方式有更好的持久化性,是由于在使用aof持久化方式时,redis会将每一个收到的写命令都通过 write 函數追加到文件中(默认是appendonly.aof). 当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

有三种方式如下(默认是:每秒 fsync 一次)

  • appendonly yes //启用aof 持久化方式
  • #appendfsync always //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
  • appendfsyne everysec //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
  • #appendfsync no //完全依赖os, 性能最好,持久化没保证

产生的问题

aof 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test
命令100次,文件中必须保存全部的100 条 命令,其实有99 条都是多余的。

Redis缓存与数据库一致性

解决方案

一、实时同步

对强一致要求比较高的,应采用实时同步方案,即查询缓存查询不到再从DB查询,保存到缓存; 更新缓存时,先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,直接设置缓存过期)。
@Cacheable: 查询时使用,注意Long类型需转换为Sting类型,否则会抛异常
@CachePut: 更新时使用,使用此注解, -一定会从 DB 上查询数据
@CacheEvict: 删除时使用;
@Caching: 组合用法

二、异步队列

对于并发程度较高的,可采用异步队列的方式同步,可采用kafka等消息中间件处理消息生产和消费。

三、使用阿里的同步工具 canal

canal 实现方式是模拟mysql slave和master的同步机制,监控DB bitlog的日志更新来触发缓存的更新,此种方法可以解放程序员双手,减少工作量,但在使用时有些局限性。

MySQL主从复制实现

  1. master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,
    binary log events ,可以通过show binlog events进行查看)
  2. slave 将master的binary log events拷贝到它的中继日志(relay log);
  3. slave 重做中继日志中的事件,将改变反映它自己的数据。

canal的工作原理:

  1. canal 模拟mysql slave 的交互协议.伪装自己为mysql slave 向mysql master发送dump协议
  2. mysql master收到dump请求,开始推送binary log给 slave(也就是canal)
  3. canal解析 binary log对象(原始为byte 流)

四、采用UDF 自定义函数的方式

面对mysql的API进行编程,利用触发器进行缓存同步,但UDF主要是c/c++语言实现,学习成本高,

Redis 主从复制

简介

应用场景:电子商务网站上的商品,一般都是一次上传,无数次浏览的,说专业点就是“多读少些”。

主从复制:

一个Redis服务可以有多个该服务的复制品,这个Redis服务称为Master,其它复制为Slaves

如图中所示,我们将一台Redis 服务器作主库(Master),其他三台作为从库(Slave),主库只负责写数据,每次有数据更新都将更新的数据同步到它所有的从库,而从库只负责读数据。这样一来,就有了两个好处:
1、读写分离,不仅可以提高服务器的负载能力,并且可以根据读请求的规模自由增加或者减少从库的数量。
2、数据被复制成了了好几份,就算有一台机器出现故障,也可以使用其他机器的数据快速恢复。
需要注意的是: 在Redis主从模式中,一台主库可以拥有多个从库,但是一个从
库只能隶属于一个主库。

Redis主从复制配置

https://www.cnblogs.com/web424/p/6908647.html

Redis Cluster 集群

简介

为什么使用redis-cluster?
为了在大流量访问下提供稳定的业务,集群化是存储的必然形态
未来的发展趋势肯定是云计算和大数据的紧密结合
只有分布式架构能满足要求

Redis集群搭建的方式有多种,但从redis 3. 0之后版本支持redis-cluster集群,至少需要3(Master) +3 (Slave)才能建立集群。Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。其redis-cluster架构图如上:

Redis Cluster 集群特点

  1. 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
  2. 节点的fail是通过集群中超过半数的节点检测失效时才生效。
  3. 客户端与redis节点直连,不需要中间proxy层客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可,
  4. redis-cluster把所有的物理节点映射到[0-16383] slot上 (不一定是平均分配) cluster负责维护
  5. Redis集群预分好 16384 个哈希槽,当需要在Redis 集群中放置一个 key-value时,redis 先对key 使用 crc16 算法算出-一个结果,然后把结果对 16384 求余数, 这样每个key 都会对应一个编号在0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点

Redis Cluster 容错

容错性: 是指软件检测应用程序所运行的软件或硬件中发生的错误并从错误中恢复的能力,通常可以从系统的可靠性、可用性、可测性等几个方面来衡量。

Redis-Cluster 节点分配

(官方推荐) 三个主节点分别是: A, B, C 三个节点,它们可以是一台机器上的三个端口,也可以是三台不同的服务器。那么,采用哈希槽(hash slot)的方式来分配16384个slot的话,它们三个节点分别承担的slot区间是
节点A覆盖9- 5460;
节点B覆盖5461 - 10922;
节点C覆盖10923 - 16383
新增一个主节点:
新增一个节点D,redis cluster的这种做法是从各个节点的前面各拿取一部分slot到D上
节点A覆盖1365 - 5460
节点B覆盖6827 - 10922
节点C覆盖12288 -16383
节点D覆盖0 - 1364, 5461-6826 ,10923 - 12287

Redus Cluster 集群搭建

简介

集群中至少应该有奇数个节点,所以搭建集群最少需要3台主机。同时每个节点至少有一个备份节点,所以下面最少需要创建使用6台机器,才能完成Redis Cluster集群(主节点、备份节点由redis-cluster集群确定)

真集群:准备 至少 6 台服务器

例: 192.168.1.1: 6379

​ 192.168.1.2: 6379

​ 192.168.1.3: 6379 .。。。。。

假集群: 在一台服务器上存在 6 个 redis 服务

例:192.168.1.1:6379 6380 6381 6382 .。。。。。

搭建流程

文献https://www.redis.com.cn/topics/cluster-tutorial

创建节点安装目录 redis_cluster

1
mkdir /usr/local/redis_cluster

在 redis_cluster 目录下,创建 7001 到 7006 文件夹

1
mkdir 7001 ......

将redis-conf 分别拷贝到 这些文件夹下

1
cp redis.conf /usr/local/redis_cluster/7001

分别修改配置文件如下内容:

同时protected-mode是为了禁止公网访问redis cache,加强redis安全的。
它启用的条件,有两个:

1、没有 bind IP

2、没有设置访问密码

由于Linux上的redis处于安全保护模式这就让你无法从虚拟机外部去轻松建立连接。
如果外部访问: redis.conf中设置保护模式为 protected-mode no

修改7001到7006下的 redis.conf 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#关闭保护模式用于公网访问
protected-mode no
port 7000

#开启集群模式
cluster-enabled yes
cluster-config-file nodes-7000.conf
cluster-node-timeout 5000

#后台启动
daemonize yes
pidfile /var/run/redis_7000.pid //可以不写
logfile "7000.log" //可以不写

#dir /redis/data
#此处绑定ip可以是阿里内网ip和本地ip也可以直接注释掉该项
bind 127.0.0.1

#用于连接主节点密码
masterauth yizhiduxiu

#设置redis密码各个节点请保持密码一致
requirepass yizhiduxiu

依次启动各个节点

将安装的redis 目录下的 src 复制到 redis_cluster下,方便启动服务器

1
2
cd redis-5.0.7
cp -r ./src/ /usr/local/redis_cluster/ //-r复制src目录下级联的所有文件

启动各个redis节点

1
2
cd /usr/local/redis_cluster
./src/redis-server ./7000/redis.conf

启动成功

创建集群

1
2
3
4
5
cd /usr/local/redis_cluster
./src/redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1 -a yizhiduxiu

# --cluster-replicas 1 表示主从配置比,1表示的是1:1,前三个是主,后三个是从
# 若配置文件中设置的密码,则还需要加上-a passwod

创建过程中可能要求输入 yes 输入yes 就完事了

Redis Cluster 集群验证

在某台机器上(或)连接集群的7001端口的节点:

1
redis-cli -h 127.0.0.1 -c -p 7001 -a yizhiduxiu  // -c 可连接到集群

加参数 -C 可连接到集群,因为上面redis.conf 将bind改为了ip地址,所以-h参数不可以省略。
(在该节点下添加对应key数据)
启动另一个集群中的客户节点:例如: 7005 .
进行读取命令。

redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节 点,就可以获取到其他节点的数据

基本命令

info replication 通过Cluster Nodes命令和Cluster Info命令来看看集群效果

测试集群数据

输入命令 cluster nodes

每个Redis的节点都有一个ID值,此ID将被此特定redls实例永久使用,以便实例在集群上下文中具有唯一的名称。每个节点都会记住 使用此ID的每个其他节点,而不是通过IP或端口。IP地址和端口可能会发生变化,但唯一的节点标识符在节点的整个生命周期内都不会改变。我们简单地称这个标识符为节点ID。

测试数据

Redis Cluster 集群 启动关闭

启动

/usr/local/redis_cluster 目录下编写脚本文件:vim start.sh

内容如下:

1
2
3
4
5
6
/usr/local/redis_cluster/src/redis-server ./7001/redis.conf
/usr/local/redis_cluster/src/redis-server ./7002/redis.conf
/usr/local/redis_cluster/src/redis-server ./7003/redis.conf
/usr/local/redis_cluster/src/redis-server ./7004/redis.conf
/usr/local/redis_cluster/src/redis-server ./7005/redis.conf
/usr/local/redis_cluster/src/redis-server ./7006/redis.conf
1
2
chmod u+x start.sh  //然后执行将start.sh 变成可执行文件
./start.sh //在当前目录下启动

关闭

/usr/local/redis_cluster 目录下编写脚本文件:vim shutdown.sh

内容如下:

1
2
3
4
5
6
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7001 -a yizhiduxiu shutdown
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7002 -a yizhiduxiu shutdown
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7003 -a yizhiduxiu shutdown
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7004 -a yizhiduxiu shutdown
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7005 -a yizhiduxiu shutdown
/usr/local/redis_cluster/src/redis-cli -c -h 127.0.0.1 -p 7006 -a yizhiduxiu shutdown
1
2
3
4
5
chmod u+x shutdown.sh  //然后执行将shutdown.sh 变成可执行文件
./shutdown.sh //在当前目录下启动
查看:ps aux | grep redis
官方:/usr/local/redis_cluster/redis-cli -a yizhiduxiu -c -h 127.0.0.1 -p 7001
提示:-a访问服务端密码, -c 表示集群模式 -h指定ip地址 -p指定端口号

开启端口权限

如果想要通过外部访问 Redis 集群,那么就要开发端口

查看已经开放的端口:

1
firewall-cmd --list-ports

开启端口:

1
firewall-cmd --zone=public --add-port=7001/tcp --permanent

重启防火墙:

1
firewall-cmd --reload

Redis Cluster总结

Redis cluster为了保证数据的高可用性,加入了主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是以主节点拉取数据备份,当这个主节点挂掉后,就会有这个从节点选取一个来充当主节点,从而保证集群不会挂掉。

集群有ABC三个主节点如果这3个节点都没有加入从节点,如果B挂掉了,我们就无法访问整个集群了, A和C的slot也无法访问,

所以我们在集群建立的时候,一定要为每个主节点都添加了从节点比如像这样,集群包含主节点A. B、 C,以及从节点A1、B1. C1, 那么即使B挂掉系统也可以继续正确工作。

B1节点替代了B节点,所以Redis集群将会选择B1节点作为新的主节点,集群将会继续正确地提供服务。当B重新开启后,它就会变成B1的从节点。

不过需要注意,如果节点B和B1同时挂了, Redis集群就无法继续正确地提供服务了。

文章作者:
文章链接: https://huohuohuohuohuohuo.github.io/2020/03/14/Redis进阶/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自
打赏
  • 微信
    微信
  • 支付寶
    支付寶

评论