redis-02

一、redis事务

Redis事务是一组命令的集合,一个事务中的所有命令都将被序列化,按照一次性、顺序性、排他性的执行一系列的命令。

1.redis事务的三大特性 

(1)单独的隔离操作

   事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

(2)没有隔离级别的概念

   队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”。

(3)不保证原子性

   redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

2.Redis事务执行的三个阶段

开启:以 MULTI 开始一个事务;

入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务      队列里面;

执行:由 EXEC 命令触发事务;

3.事务的基本操作

multi --》开启事务

exec --》执行事务

discard  --》放弃事务

4.事务的注意事项

① 命令集合中含有错误的指令(注意是语法错误),均连坐,全部失败。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k3 1
QUEUED
127.0.0.1:6379(TX)> get k3 
QUEUED
127.0.0.1:6379(TX)> set k3
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> exec
(error) EXECABORT Transaction discarded because of previous errors

 ② 运行时错误,即非语法错误,正确命令都会执行,错误命令返回错误。

127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set name zhangsan
QUEUED
127.0.0.1:6379(TX)> incr name
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) (integer) 2
3) "2"
4) OK
5) (error) ERR value is not an integer or out of range
6) "zhangsan"

二、redis主从复制

 将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave),数据的复制是单向的,只能由主节点到从节点。

1.主从复制的作用  

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

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

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

  4. 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

 2.主从复制搭建

①新建redis6379.conf , redis6380.conf , redis6381.conf

include /usr/local/redis/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

 ②启动三台redis服务器

redis-server ./redis6379.conf
redis-server ./redis6380.conf
redis-server ./redis6381.conf

③查看三台主机运行情况

#打印主从复制的相关信息
./redis-cli -p 6379
./redis-cli -p 6380
./redis-cli -p 6381
127.0.0.1:6379> info replication
127.0.0.1:6380> info replication
127.0.0.1:6381> info replication

④配从库不配主库

语法格式:
slaveof <ip> <port>

例如:
127.0.0.1:6380> SLAVEOF 192.168.8.129 6379

⑤验证主从复制

在主机上写,在从机上可以读取数据

3.主从复制原理

主从复制可以分为3个阶段

  • 连接建立阶段(即准备阶段)

  • 数据同步阶段

  • 命令传播阶段

复制过程大致分为6个过程

①保存主节点(master)信息。

②从节点(slave)内部通过每秒运行的定时任务维护复制相关逻辑,当定时任务发现存在新的主节点后,会尝试与该节点建立网络连接

③从节点与主节点建立网络连接

        从节点会建立一个 socket 套接字,从节点建立了一个端口为51234的套接字,专门用于接受主节点发送的复制命令

④发送ping命令

        连接建立成功后从节点发送 ping 请求进行首次通信。

作用:

  • 检测主从之间网络套接字是否可用。

  • 检测主节点当前是否可以接受命令 。

⑤权限验证。

        如果主节点设置了 requirepass 参数,则需要密码验证,从节点必须配置 masterauth 参数保证与主节点相同的密码才能通过验证;如果验证失败复制将终止,从节点重新发起复制流程。

⑥同步数据集。

        主从复制连接正常通信后,对于首次建立复制的场景,主节点会把持有的数据全部发送给从节点,这部分操作是耗时最长的步骤。

⑦主从同步策略

主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。当然,如果有需要,slave 在任何时候都可以发起全量同步。 redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

三、redis哨兵监控

1.哨兵监控

        解决了主从复制的缺点:当主机 Master 宕机以后,我们需要人工解决切换

2.哨兵模式概述

        哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

3.哨兵监控的作用

集群监控:负责监控redis master和slave进程是否正常工作

消息通知:如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员

故障转移:如果master node挂掉了,会自动转移到slave node上

配置中心:如果故障转移发生了,通知client客户端新的master地址

4.哨兵模式搭建

①编写配置文件

新建sentinel-26379.conf、sentinel-26380.conf 、sentinel-26381.conf 文件  

#端口
port 26379
#守护进程运行
daemonize yes
#日志文件
logfile "26379.log"
sentinel monitor mymaster 192.168.8.129 6379 2

另外两个端口号和日志文件不同

参数说明

sentinel monitor mymaster 192.168.8.129 6379 2 配置的含义是:该哨兵节点监控192.168.8.129:6379这个主节点,该主节点的名称是mymaster,最后的2的含义与主节点的故障判定有关:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移。

②启动哨兵节点

redis-sentinel sentinel-26379.conf
redis-sentinel sentinel-26380.conf
redis-sentinel sentinel-26381.conf

 ③查看哨兵状态

[root@localhost src]# ./redis-cli -p 26379
127.0.0.1:26379>
127.0.0.1:26379>
127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.8.129:6379,slaves=2,sentinels=3

④测试故障转移,使用kill命令杀掉主节点

#查看redis相关的服务信息
 ps -ef | grep redis
#使用kill -9 进程ID 杀死redis-server:6379服务

⑤再次查看哨兵节点信息

127.0.0.1:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
sentinel_simulate_failure_flags:0
master0:name=mymaster,status=ok,address=192.168.8.129:6380,slaves=2,sentinels=3

⑥在新主节点写数据,其他节点读数据

127.0.0.1:6380> set k6 v6
OK

127.0.0.1:6381> get k6
"v6"

5.哨兵监控的原理

分为四个阶段:

①监控阶段

  1. sentinel(哨兵1)----->向master(主)和slave(从)发起info,拿到全信息。

  2. sentinel(哨兵2)----->向master(主)发起info,就知道已经存在的sentinel(哨兵1)的信息,并且连接slave(从)。

  3. sentinel(哨兵2)----->向sentinel(哨兵1)发起subscribe(订阅)。

② 通知阶段

sentinel不断的向master和slave发起通知,收集信息。

③故障转移阶段

 通知阶段sentinel发送的通知没得到master的回应,就会把master标记为SRI_S_DOWN,并且把master的状态发给各个sentinel,其他sentinel听到master挂了,说我不信,我也去看看,并把结果共享给各个sentinel,当有一半的sentinel都认为master挂了的时候,就会把master标记为SRI_0_DOWN。

④投票阶段

方式: 自己最先接到哪个sentinel的竞选通知就会把票投给它。

剔除一些情况:

  1. 不在线的

  2. 响应慢的

  3. 与原来master断开时间久的

  4. 优先级原则

四、Redis集群

Redis有三种集群模式

  • 主从模式

  • Sentinel模式

  • Cluster模式

 1.哨兵模式的缺点

  1. 当master挂掉的时候,sentinel 会选举出来一个 master,选举的时候是没有办法去访问Redis的,会存在访问瞬断的情况;

  2. 哨兵模式,对外只有master节点可以写,slave节点只能用于读。尽管Redis单节点最多支持10W的QPS,但是在电商大促的时候,写数据的压力全部在master上。

  3. Redis的单节点内存不能设置过大,若数据过大在主从同步将会很慢;在节点启动的时候,时间特别长;

 2.redis集群的优点

  • Redis集群 是一个由多个主从节点群组成的分布式服务集群,它具有复制、高可用和分片特性。

  • Redis集群有多个master,可以减小访问瞬断问题的影响

  • Redis集群有多个master,可以提供更高的并发量 

  • Redis集群可以分片存储,这样就可以存储更多的数据

3.Redis Cluster模式搭建

① 准备环境

第1台机器: 192.168.8.101 8001端口 8002端口
第2台机器: 192.168.8.102 8001端口 8002端口
第3台机器: 192.168.8.103 8001端口 8002端口

 ②配置集群环境

        创建文件夹

mkdir -p /usr/local/redis-cluster/8001 /usr/local/redis-cluster/8002

        拷贝配置文件

                将redis安装目录下的 redis.conf 文件分别拷贝到8001和8002目录下

cp /usr/local/redis-6.2.6/redis.conf /usr/local/redis-cluster/8001
cp /usr/local/redis-6.2.6/redis.conf /usr/local/redis-cluster/8002

        修改redis.conf文件以下内容 8001

# 端口
port 8001
# 后台启动
daemonize yes
# 进程id
pidfile "/var/run/redis_8001.pid"
#指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据
dir /usr/local/redis-cluster/8001/
#启动集群模式
cluster-enabled yes
#集群节点信息文件,这里800x最好和port对应上
cluster-config-file nodes-8001.conf
# 节点离线的超时时间
cluster-node-timeout 5000
#去掉bind绑定访问ip信息
#bind 127.0.0.1
#关闭保护模式
protected-mode no
#启动AOF文件
appendonly yes
#如果要设置密码需要增加如下配置:
#设置redis访问密码
#requirepass 123456
#设置集群节点间访问密码,跟上面一致
#masterauth 123456

将本台机器文件拷贝到另外两台机器上,需要修改端口号以及文件

③启动集群

redis-server /usr/local/redis-cluster/8001/redis.conf
redis-server /usr/local/redis-cluster/8002/redis.conf

创建集群

redis-cli -a redis-pw --cluster create --cluster-replicas 1 \
192.168.8.101:8001 192.168.8.101:8002	\
192.168.8.102:8001 192.168.8.102:8002	\
192.168.8.103:8001 192.168.8.103:8002	\

④测试集群

redis-cli -a redis-pw -c -h 192.168.8.101 -p 8001

⑤查看集群的信息

cluster info

4.Redis Cluster 原理

Redis Cluster将所有数据划分为16384个slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。只有master节点会被分配槽位,slave节点不会分配槽位。

槽位定位算法: k1 = 127001

Cluster 默认会对 key 值使用 crc16 算法进行 hash 得到一个整数值,然后用这个整数值对 16384 进行取模来得到具体槽位。

HASH_SLOT = CRC16(key) % 16384

命令执行 
set k1 v1

注意:

根据k1计算出的槽值进行切换节点,并存入数据。不在一个slot下的键值,是不能使用mget、mset等多建操作。

 可以通过{}来定义组的概念,从而是key中{}内相同内容的键值对放到同一个slot中。

mset k1{test} v1 k2{test} v2 k3{test} v3

查看节点

192.168.8.101:8001> cluster nodes

5.SpringDataRedis 连接集群

①添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

②编写配置文件

spring:
  redis:
    cluster:
      nodes: 192.168.184.137:8001,192.168.184.137:8002,192.168.184.138:8001,192.168.184.138:8002,192.168.184.139:8001,192.168.184.139:8002

③编写测试

@SpringBootTest
class RedisDemo2ApplicationTests {
    @Autowired
    private RedisTemplate redisTemplate;
    @Test
    void contextLoads() {
        redisTemplate.opsForValue().set("k6","v6");
        System.out.println(redisTemplate.opsForValue().get("k6"));
    }
}

五、Redis常见问题探析

1.Redis脑裂问题解决?

答:Redis主从模式下,由于主节点挂了,从节点新选出主节点,由于网络情况,挂掉主节点没有降级为从节点,导致有两个主节点可以写数据。导致挂掉的主节点的数据无法同步而丢失问题。解决办法:

redis.conf配置参数:

min-replicas-to-write 1
min-replicas-max-lag 5

2.如何解决缓存冷启动问题?

答:冷启动是指服务器缓存中没有数据直接启动,访问量有比较大,mysql直接裸机运行。通过缓存预热解决,通过storm实时计算出热点数据,然后定时将热点数据写入缓存。

3.如何解决缓存穿透问题?

答:查询一个redis和mysql肯定都不存在的数据是缓存穿透,例如查询id为-1的数据,多半为认为恶意攻击。解决方案:去数据库查不存在在redis存null,并且设置过期时间5分钟。

或者用布隆过器解决:布隆过滤器是一个bitMap数组,它说不存在的元素一定不存在,他说存在的未必存在。

4.如何缓存击穿问题?

答:某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。从造成问题的原因去解决,当热点Key失效的一刹那,大并发裸奔访问数据库,数据库被打垮。我们只需要在热点Key失效的一刹那保证只有一个请求过来就可以了。这种需求肯定用锁解决,理论上可以用同步锁解决,但这个不靠谱,锁只能锁一个进程,但是微服务是多个服务是多个进程,根本不起作用。所以用分布式锁解决。

5.如何解决缓存雪崩问题?

答:大量缓存同时失效,数据库被击垮问题。解决思路不让缓存同时失效,比如加给缓存过期时间加随机数,但是当缓存数据足够大时,这个效果不那么明显了,可以通过二级缓存技术实现。

        先查询本地nginx缓存查询有没有数据,有数据,直接返回;nginx缓存没有数据再去redis分布式缓存查询,如果有将redis缓存同步nginx缓存在返回;如果redis没有,取数据库查询,数据库存在将数据同步到redis并返回。只要nginx的过期时间和redis的过期时间不一样就解决了缓存雪崩问题,并合理使用了本地缓存和分布式缓存。

六、Redis 开发规范

1.key设计技巧

  1. 把表名转换为key前缀,如 tag:

  2. 把第二段放置用于区分key的字段,对应msyql中主键的列名,如 user_id

  3. 第三段放置主键值,如 2,3,4

  4. 第四段写存储的列名

#   表名 主键 主键值 存储列名字
set user:user_id:1:name 张三
set user:user_id:1:age 20

2.value设计

拒绝bigkey

防止网卡流量、慢查询,string类型控制在10KB以内,hash、 list、set、zset元素个数不要超过5000。

3.命令使用

  1. 禁用命令 :禁止线上使用keys、flushall、flushdb等,通过redis的rename机制禁掉命令,或者使用scan的方式渐进式处理。

  2. 合理使用select :redis的多数据库较弱,使用数字进行区分,很多客户端支持较差, 同时多业务用多数据库实际还是单线程处理,会有干扰。

  3. 使用批量操作提高效率

    1. 原生命令:例如mget、mset。

    2. 非原生命令:可以使用pipeline提高效率

    3. 注意:但要注意控制一次批量操作的元素个数(例如500以内,实际也和元素字节数有关)。

    4. 不建议过多使用Redis事务功能

      Redis的事务功能较弱(不支持回滚),而且集群版本(自研和官方)要求一次事务操作的key必须在一个slot上。

4.Redis 数据一致性问题

解决方案

先更新数据库,再延时删缓存

 

这种情况存在并发问题吗?

(1)缓存刚好失效

(2)请求A查询数据库,得一个旧值

(3)请求B将新值写入数据库

(4)请求B删除缓存

(5)请求A将查到的旧值写入缓存

发生这种情况的概率又有多少?

发生上述情况有一个先天性条件,就是步骤(3)的写数据库操作比步骤(2)的读数据库操作耗时更短,才有可能使得步骤(4)先于步骤(5)。可是,大家想想,数据库的读操作的速度远快于写操作的,因此步骤(3)耗时比步骤(2)更短,这一情形很难出现。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值