redis

Redis 目前被广泛应用,缓存、限流、PubSub、分布式锁、分布式数据结构等等许多场景都十分实用。

安装

docker run -p 6379:6379 --name rediss -v /root/redism.conf:/data/redis.conf -d redis redis-server /data/redis.conf --appendonly yes

安装sentinel

docker run --name redis1-sentinel -v /root/sentinel.conf:/data/sentinel.conf -d redis redis-sentinel /data/sentinel.conf

官方配置文件下载:

wget http://download.redis.io/redis-stable/sentinel.conf

docker 创建的redis 默认不会有配置文件需要映射,添加密码可以再后面补充--requirepass password 或者在配置文件中配置

主从配置 slaveof

主从配置优缺点

数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。

故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。

负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。

Master主机写压力任然很大: 负载均衡增大了并发量,但是写入压力依然没有改变。

同步方式

  1. 首次同步时主服务器执行BGSAVE命令生存RDB文件发送给从服务器进行同步

  2. 断线后再次同步时,从服务器发送当前偏移量,如果偏移地址的的数据还存在复制积压缓冲区(默认大小1M)则执行部分同步,反之生存RDB文件执行全量同步

  3. 每次同步都会比较自己保存的Master服务器的Id,如果一直才会进行同步

主节点和从节点之间通过同步写命令来保持数据一致(在启动的时候会立刻先同步主节点的快照,保存主节点的信息)

实现主从

可以执行命令 slaveof 和通过修改配置文件 redis.conf 中的 slaveof 来实现主从

如果redis 有添加密码,则还需要配置或执行命令 masterauth password

SLAVEOF host port

SLAVEOF 命令用于在 Redis 运行时动态地修改复制(replication)功能的行为。

通过执行 SLAVEOF host port 命令,可以将当前服务器转变为指定服务器的从属服务器(slave server)。

如果当前服务器已经是某个主服务器(master server)的从属服务器,那么执行 SLAVEOF host port 将使当前服务器停止对旧主服务器的同步,丢弃旧数据集,转而开始对新主服务器进行同步。

另外,对一个从属服务器执行命令 SLAVEOF NO ONE 将使得这个从属服务器关闭复制功能,并从从属服务器转变回主服务器,原来同步所得的数据集不会被丢弃。

利用『 SLAVEOF NO ONE 不会丢弃同步所得数据集』这个特性,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行。

info replication

查看主从状态命令

结果大概这样

# Replication
role:master
connected_slaves:2
slave0:ip=172.17.0.3,port=6379,state=online,offset=56,lag=0
slave1:ip=172.17.0.4,port=6379,state=online,offset=56,lag=1
master_failover_state:no-failover
master_replid:a7a1f8df384308fe4370329edb5a50c37b2986f9
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:56
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:56

额外可能用上的命令说明:

docker inspect 获取原数据,可以用来查看容器ip

docker logs container --tail 10 查看容器最后10行的日志

哨兵模式(sentinel)

Sentinel 负责监控 Redis Master,同时 Sentinel 集群之间通过 Master 进行通讯。Sentinel 以集群保障自身的可靠性,官方建议 Sentinel 至少保持3个节点。Sentinel为官方高可靠的解决方案。

Sentinel 提供以下特性(来自官网):

监控(Monitoring):持续检查 master、slave 健康状况

提醒(Notification):当Redis实例出问题时,可以通过系统管理员或以API形式通知其他应用。
自动故障转移(Automatic failover):当master发生故障时,Sentinel 会开启故障处理流程,将一个slave晋升为master,并将其他slave重新配置到新的master。当应用进行连接时,Sentinel会将新的master告知应用。

配置提供者(Configuration provider):Sentinel 为客户端提供master节点的地址,当发生故障时,负责报告新的master节点给客户端。

1、异步数据丢失。

2、脑裂问题

Redis 单机有单点故障,Master-Slave 无法做自动故障转移,可以使用官方推荐的 Sentinel 实现Redis高可用方案。

redis 与 RabbitMQ 的比较

可靠性

redis :没有相应的机制保证消息的可靠消费,如果发布者发布一条消息,而没有对应的订阅者的话,这条消息将丢失,不会存在内存中;
rabbitmq:具有消息消费确认机制,如果发布一条消息,还没有消费者消费该队列,那么这条消息将一直存放在队列中,直到有消费者消费了该条消息,以此可以保证消息的可靠消费;

实时性

redis:实时性高,redis作为高效的缓存服务器,所有数据都存在在服务器中,所以它具有更高的实时性

消费者负载均衡

rabbitmq队列可以被多个消费者同时监控消费,但是每一条消息只能被消费一次,由于rabbitmq的消费确认机制,因此它能够根据消费者的消费能力而调整它的负载;
redis发布订阅模式,一个队列可以被多个消费者同时订阅,当有消息到达时,会将该消息依次发送给每个订阅者;

持久性

redis:redis的持久化是针对于整个redis缓存的内容,它有RDB和AOF两种持久化方式(redis持久化方式,后续更新),可以将整个redis实例持久化到磁盘,以此来做数据备份,防止异常情况下导致数据丢失。
rabbitmq:队列,消息都可以选择性持久化,持久化粒度更小,更灵活;

队列监控

rabbitmq实现了后台监控平台,可以在该平台上看到所有创建的队列的详细情况,良好的后台管理平台可以方面我们更好的使用;
redis没有所谓的监控平台。

总结

redis: 轻量级,低延迟,高并发,低可靠性;
rabbitmq:重量级,高可靠,异步,不保证实时;
rabbitmq是一个专门的AMQP协议队列,他的优势就在于提供可靠的队列服务,并且可做到异步,而redis主要是用于缓存的,redis的发布订阅模块,可用于实现及时性,且可靠性低的功能

故障转移转移是做什么

1.选举Mater服务器

2.让没有选为Master的服务器变为复制新的主服务器

3.让下线服务器上线后变为从服务器

为什么两个节点为什么redis哨兵集群只有2个节点无法正常工作?

判断节点是否宕机并且需要重启需要几个哨兵协同判断,当一定数量的哨兵(可配置) 认为主节点宕机才会去升级从节点
当只有一个节点的时候正确的执行故障转移,服务还是读库状态当写的时候就会出问题

事务(ACID)的特点

Redis通过 MULTI,EXEC,WATCH,DISCARD 四个命令来操作事务。

事务执行分为三个部分:1. 开始事务,2. 命令入队 3. 执行事务

只有收到上面四个特殊命令时才会执行事务,不然一直当命令处理

原子性: Redis 具有原子性,如果在命令入队期间出现错误,事务将拒绝提交,如果在执行事务阶段出错事务将跳过错误继续执行

一致性:不管在执行事务阶段出错,导致数据没有保存,还是保存阶段宕机都能够保证一致性,因为数据都没有进入redis,或者所有数据库都是空数据

隔离性:因为Redis是单线程所以一定有隔离性

持久性:因为事务只是简单的包裹了为一组命令,所以在一些情况下不具备持久性

  1. redis在无持久化模式下因为数据只在内存中所以不具备持久性
  2. 在RDB模式下,只有满足条件才会被执行BGSAVE命令进行保存,在加上是异步执行的命令,不能保证在事务数据在第一时间保存到硬盘,因此也不具备持久性
  3. AOF模式下只有appendfsync 选项为"always" 才具备持久性,为everysec和no时不能保证持久性,everysec 为每秒保存,no时交由操作系统来决定保存时机,所以不能第一时间进行保存

如果 no-appendfsync-on-rewrite命令处于打开状态,则如果正好在执行BGSAVE 或者 BGREWRITEAOF 命令时,会停止对AOF文件的同步来减少I/O阻塞,这时候appendfsyncalways保证持久性的说法不成立

WATCH 命令说明
watch 是一个乐观锁,当监视一个key值时,另外一个用户修改了这个值,则事务提交失败

redis> watch "key"
redis> multi
reids>set "key" "value"  --在这命令执行后数据被人修改,事务失败
redis>exec

事务的提交后主要失败问题有,比如对一个string类型的数据执行push命令

分布式锁 ( redis sentx )

关于分布式锁,一般有三种选择,
1、redis
2、ZooKeeper
3、DB锁(悲观锁、乐观锁)

其中用的最多的应该是redis。

redis常用的方式有单节点、主从模式、哨兵模式、集群模式。

单节点在生产环境基本上不会使用,因为不能达到高可用,且连RDB或AOF备份都只能放在master上,所以基本上不会使用。

另外几种模式都无法避免两个问题:

1、异步数据丢失。

2、脑裂问题。

所以redis官方针对这种情况提出了红锁(Redlock)的概念。

假设有5个redis节点,这些节点之间既没有主从,也没有集群关系。客户端用相同的key和随机值在5个节点上请求锁,请求锁的超时时间应小于锁自动释放时间。当在3个(超过半数)redis上请求到锁的时候,才算是真正获取到了锁。如果没有获取到锁,则把部分已锁的redis释放掉。

附上官方Redlock链接地址: https://redis.io/topics/distlock

一、锁丢失

Redis的master节点上拿到了锁;
但是这个加锁的key还没有同步到slave节点;
master故障,发生故障转移,slave节点升级为master节点;
导致锁丢失。

二、持有同一把锁(竞态模型场景)

为了避免Redis宕机引起锁服务不可用, 需要为Redis实例(master)增加热备(slave),如果master不可用则将slave提升为master。这种主从的配置方式存在一定的安全风险,由于Redis的主从复制是异步进行的, 可能会发生多个客户端同时持有一个锁的现象。

竞态模型:

1、Client A 获得在master节点获得了锁

2、在master将key备份到slave节点之前,master宕机

3、slave 被提升为master

4、Client B 在新的master节点处获得了锁,Client A也持有这个锁。

解决思路

简单来说是过半机制。

一个客户端需要做如下操作来获取锁:

1、获取当前时间(单位是毫秒)。

2、轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。比如如果锁自动释放时间是10秒钟,那每个节点锁请求的超时时间可能是5-50毫秒的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。

3、客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁(在这里是3个),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。

4、如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。

5、如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,客户端都会到每个master节点上释放锁,即便是那些他认为没有获取成功的锁。

数据类型

SDS 是sdshdr.h 结构:优化了长度获取和内存分配(分配规则以1M为分界点 N<1M 分配的空间N×2 超出则每次N+1M) 可以保持二进制。

posted on 2021-11-09 10:39  好怀念啊  阅读(40)  评论(0编辑  收藏  举报