Redis笔记(四)初识Redis Cluster & 深入Redis Cluster & 缓存设计与优化

初识Redis Cluster & 深入Redis Cluster & 缓存设计与优化

在这里插入图片描述
实验部分对应 Redis笔记(四)实验部分:redisCluster的原生安装与官方工具安装

第9章 初识Redis Cluster

Redis Cluster是Redis 3提供的分布式解决方案,有效解决了Redis分布式方面的需求,同时它也是学习分布式存储的绝佳案例。本章将针对Redis Cluster的数据分布,搭建集群进行分析说明。

9-1 本章目录

  1. 呼唤集群
  2. 数据分布
  3. 搭建集群
  4. 集群伸缩
  5. 客户端路由
  6. 集群原理
  7. 开发运维常见问题

9-2 呼唤集群

为什么呼唤

  1. 并发量
    在这里插入图片描述

  2. 数据量
    在这里插入图片描述

  3. 网络流量

“解决方法"
配置“强悍”的机器:超大内存、牛xCPU等

正确的解决方法
分布式:简单的认为加机器

9-3 数据分布概论

在这里插入图片描述

两种分区方式

在这里插入图片描述
两种数据分布对比
在这里插入图片描述

9-4 节点取余分区

在这里插入图片描述

扩容

若添加一个节点在下面途中会有8成的迁移量
在这里插入图片描述
但如果采用翻倍扩容(比如下面 的六个 需要迁移的数据量将大大降低)
在这里插入图片描述

优缺点

优点: 客户端分片,使用 哈希+取余较为简单
缺点:节点伸缩时数据节点关系变化,会导致数据迁移,而迁移数量和添加节点数量有关所以建议翻倍扩容

9-5 一致性哈希分区

一个tocken环的长度设为 0~2的32次方,放置四个节点,新添加的key则会顺势针的找到最近的node
在这里插入图片描述

扩容

若添加n5 则变动的数据仅为n1和n2之间的 ,需要变动(回写)的数据就会减少
在这里插入图片描述

优缺点

优点
客户端分片:哈希+顺时针(优化取余)
节点伸缩:只影响邻近节点,但是还是有数据迁移
缺点
添加n5后,会使除 n2 n5外的节点的数据量相对更大 因此建议使用翻倍伸缩,保证最小迁移数据和负载均衡

9-6 虚拟槽哈希分布

  1. 预设虚拟槽:每个槽映射一个数据子集,一般比节点数大
  2. 良好的哈希函数:例如CRC16
  3. 服务端管理节点、槽、数据:例如Redis Cluster
    在这里插入图片描述

9-7 基本架构

分布式架构中每个节点都会负责读和写 并且彼此能够相互通信
在这里插入图片描述
Redis Cluster架构

  1. 节点
# 节点集群模式启动该节点
cluster-enabled:yes
  1. meet 几点之前要达到互通
    在这里插入图片描述

  2. 指派槽
    在这里插入图片描述

  3. 复制

9-8 原生安装

#准备节点
节点握手
分配槽
分配主从

9-9 工具安装

第10章 深入Redis Cluster

本章将针对Redis Cluster的集群伸缩,请求路由,故障转移等方面进行分析说明。

10-1 集群伸缩目录

主要分为三个部分 集群的扩容与缩容及其伸缩的原理

10-2 集群伸缩原理

下图代表节点的加入与下线
在这里插入图片描述
下图是一个“伸”的过程,即将节点加入6385加入集群,该过程需要meet操作 和槽的分配。
在这里插入图片描述
其实集群伸缩就等于是槽和数据在节点之间的移动

10-3 集群的扩展

10-3-1 扩展集群-1.加入节点

准备新节点

新节点:

  • 集群模式
  • 配置和其他节点统一·启动后是孤儿节点。
redis-server conf/redis-6385.conf
redis-server conf/redis-6386.conf

启动两个孤立节点之后集群结构如下:

在这里插入图片描述

加入集群
127.0.0.1:6379>cluster meet 127.0.0.1 6385
127.0.0.1:6379>cluster meet 127.0.0.1 6386

加入之后如下
在这里插入图片描述
加入集群有两个作用

  • 为它迁移槽和数据实现扩容
  • 作为从节点负责故障转移

当然也可以使用官方工具进行加入节点

redis-trib.rb add-node new_host:new port existing_host:existing port --slave --master-id <arg>
redis-trib.rb add-node 127.0.0.1:6385 127.0.0.1:6379

使用redis-trib.rb能够避免新节点已经加入了其他集群,造成故障。

迁移槽和数据

主要分为三步

槽迁移计划

分配给新节点一定的槽数:
在这里插入图片描述

迁移数据
  1. 对目标节点发送:cluster setslot {slot} importing {sourceNodeld}命令,让目标节点准备导入槽的数据。
  2. 对源节点发送:cluster setslot {slot} migrating {targetNodeld}命令,让源节点准备迁出槽的数据。
  3. 源节点循环执行cluster getkeysinslot {slot){count} 命令,每次获取count个属于槽的健。
  4. 在源节点上执行migrate {targetlp} {targetPort} key 0 {timeout} 命令把指定key迁移。
  5. 重复执行步骤3~4直到槽下所有的键数据迁移到目标节点。
  6. 向集群内所有主节点发送cluster setslot {slot} node {targetNodeld}命令,通知槽分配给目标节点。

在这里插入图片描述

添加从节点

10-3-2 集群扩容演示-1

10-3-3 集群扩容演示-2

10-4 集群的缩容

10-4-1 集群缩容-说明

10-4-2 集群缩容-操作

10-5客户端路由

10-5-1 moved异常说明和操作

在这里插入图片描述
下图是指向自身 之后槽命中的效果
在这里插入图片描述
槽不命中:moved异常
在这里插入图片描述
下面的实例演示中先 添加 -c 参数以集群方式启动 可以看到 键值为hello是直接命中了节点 键值为php时出现了moved异常 并且帮我们完成跳转成7001客户端。
而不使用 -c 参数时则会直接返回异常
在这里插入图片描述

10-5-2 ask重定向

由于槽迁移而客户端中所保存的地址不变会造成访问上的问题 这就有了ask重定向异常
在这里插入图片描述
在这里插入图片描述
moved和ask的比较

  1. 两者都是客户单重定向
  2. moved:槽已经确定迁移
  3. ask:槽还在迁移中

10-5-3 smart客户端实现原理

smart客户端原理主要就在于追求性能:

  1. 从集群中选一个可运行节点,使用cluster slots初始化槽和节点映射。
  2. 将cluster slots的结果映射到本地,为每个节点创建JedisPool。
  3. 准备执行命令。

其中执行命令是smart客户端的核心过程
JedisCluster中 存储的是 key及其对应的槽的位置 和改槽所在的节点
若目标节点返回出错则会随机请求一个节点 这个过程大概率会发生 moved异常然后就会重置本地缓存 如果五次未成功则返回异常

大致流畅图如下:
在这里插入图片描述

10-5-4 JedisCluster执行源码分析

10-6 smart客户端JedisCluster

10-6-1 JedisCluster基本使用

10-6-2 整合spring-1

10-6-3 整合spring-2

10-6-4 多节点操作命令

在这里插入图片描述

10-6-5 批量操作优化

批量操作怎么实现?
mget mset必须在一个槽

四种批量优化的方法:

  1. 串行mget

在这里插入图片描述
2. 串行IO
其实就是对上面的改进 通过sunKeys按照所属节点聚合分组 降低传输次数
在这里插入图片描述
3. 并行IO
使用多线程进行并行操作
在这里插入图片描述
4. hash_tag
使用tag进行包装 效率更高 全部请求到一个节点上
在这里插入图片描述
四种方式比较
在这里插入图片描述

10-7 故障转移

10-7-1 故障发现

◆通过ping/pong消息实现故障发现:不需要sentinel
◆主观下线和客观下线

主观下线

定义:某个节点认为另一个节点不可用,“偏见"
主管下线流程:
在这里插入图片描述
其中 pfail就代表是主管下线

客观下线

定义:当半数以上持有槽的主节点都标记某节点主观下线
客观下线流程:一个主节点接收到其它节点的ping消息 并且该节点会维护每个节点及其对应的pfail信息的一个列表

在这里插入图片描述

尝试客观下线的流程
在这里插入图片描述
该节点的作用有两个:

  1. 通知集群内所有节点标记故障节
  2. 点为客观下线通知故障节点的从节点触发故障
    转移流程

10-7-2 故障恢复

故障恢复主要分为四步:

资格检查
  1. 每个从节点检查与故障主节点的断线时间。
  2. 超过cluster-node-timeout*cluster-slave-validity-factor取消资格。
  3. cluster-slave-validity-factor:默认是10
    cluster-node-timeout默认是15
    即可得知 时间超过150秒则取消资格
备选举时间

在这里插入图片描述
上图b-1节点偏移量 更大意味着丢失数据更小 所以要给予偏袒 让其延迟一秒就参与选举以获得更多的票数。

选举投票

获得票数过半即可替换主节点
在这里插入图片描述

替换主节点
  1. 当前从节点取消复制变为主节点。(slaveof no one)
  2. 执行clusterDelSlot撤销故障主节点负责的槽,并执行clusterAddSlot把这些槽分配给自己。
  3. 向集群广播自己的pong消息,表明已经替换了故障从节点

10-7-3 故障模拟

10-8 Redis Cluster常见开发运维问题

10-8-1 集群完整性

cluster-require-full-coverage默认为yes(即所有节点和槽可用集群才提提供服务)

  1. 集群中16384个槽全部可用:保证集群完整性
  2. 节点故障或者正在故障转移:
    (error)CLUSTERDOWN The cluster is down

大多数业务无法容忍,cluster-require-full-coverage建议设置为no

10-8-2 带宽消耗

在这里插入图片描述

体现在三个方面:

  1. 消息发送频率:节点发现与其它节点最后通信时间超过cluster-node-timeout/2时会直接发送ping消息
  2. 消息数据量:slots槽数组(2KB空间)和整个集群1/10的状态数据(10个节点状态数据约1KB)
  3. 节点部署的机器规模:集群分布的机器越多且每台机器划分的节点数越均匀,则集群内整体的可用带宽越高。

举例

  1. 规模:节点200个、20台物理机(每台10个节点)
  2. cluster-node-timeout=15000,ping/pong带宽为25Mb
  3. cluster-node-timeout=20000,ping/pong带宽低于15Mb

优化

  1. 避免“大”集群:避免多业务使用一个集群,大业务可以多集群。
  2. cluster-node-timeout:带宽和故障转移速度的均衡。
  3. 尽量均匀分配到多机器上:保证高可用和带宽

10-8-3 Pub/Sub广播

在这里插入图片描述
问题:publish在集群每个节点广播:加重带宽
解决:单独“走”一套Redis Sentinel

10-8-4 集群倾斜-目录

在这里插入图片描述

10-8-5 数据倾斜

  1. 节点和槽分配不均
redis-trib.rb info ip:port 查看节点、槽、键值分布
redis-trib.rb rebalance ip:port 进行均衡(谨慎使用)
  • 不同槽对应键值数量差异较大
    CRC16正常情况下比较均匀。
    可能存在hash_tag ,可通过cluster countkeysinslot {slot}获取槽对应键值个数

  • 包含bigkey
    bigkey:例如大字符串、几百万的元素的hash、set等
    可以在从节点执行:redis-cli --bigkeys查看bigkey
    优化:优化数据结构。

  • 内存相关配置不一致
    hash-max-ziplist-value、set-max-intset-entries等
    优化:定期“检查”配置一致性

10-8-6 请求倾斜

热点key:

  • 重要的key或者bigkey

优化:

  • 避免bigkey
  • 热键不要用hash_tag
  • 当一致性不高时,可以用本地缓存+MQ

10-8-7 读写分离

只读连接:集群模式的从节点不接受任何读写请求。

  • 重定向到负责槽的主节点
  • readonly命令可以读:连接级别命令

读写分离:更加复杂

  • 同样的问题:复制延迟、读取过期数据、从节点故障
  • 修改客户端:cluster slaves{nodeld}

10-8-9 数据迁移

官方迁移工具:redis-trib.rb import

  • 只能从单机迁移到集群
  • 不支持在线迁移:source需要停写
  • 不支持断点续传
  • 单线程迁移:影响速度

在线迁移:

  • 唯品会redis-migrate-tool
  • 豌豆荚:redis-port

10-8-10 集群vs单机

集群的限制

  1. key批量操作支持有限:例如mget、mset必须在一个slot
  2. Key事务和Lua支持有限:操作的key必须在一个节点
  3. key是数据分区的最小粒度:不支持bigkey分区
  4. 不支持多个数据库:集群模式下只有一个db0
  5. 复制只支持一层:不支持树形复制结构

分布式redis不一定好用:
1.Redis Cluster:满足容量和性能的扩展性,很多业务”不需要”。

 大多数时客户端性能会”降低"。
 命令无法跨节点使用:mget、keys、scan、flush、sinter等。
 Lua和事务无法跨节点使用。
 客户端维护更复杂:SDK和应用本身消耗(例如更多的连接池)。

2.很多场景Redis Sentinel已经足够好。

第11章 缓存设计与优化

讲解将缓存加入应用架构后带来的一些问题,这些问题常常会成为应用的致命点。

11-1 目录

11-2 缓存的受益和成本

受益

1.加速读写
通过缓存加速读写速度:CPUL1/L2/L3 Cache、Linux page Cache加速硬盘读写、浏览器缓存、Ehcache缓存数据库结果。
2.降低后端负载
后端服务器通过前端缓存降低负载:业务端使用Redis降低后端MySQL负载等

成本

1.数据不一致:缓存层和数据层有时间窗口不一致,和更新策略有关。
2.代码维护成本:多了一层缓存逻辑。
3.运维成本:例如Redis Cluster

使用场景

1.降低后端负载:
对高消耗的SQL:join结果集/分组统计结果缓存。
2.加速请求响应:
利用Redis/Memcache优化IO响应时间
3.大量写合并为批量写:
如计数器先Redis累加再批量写DB

11-3 缓存的更新策略

1.LRU/LFU/FIFO算法剔除:例如maxmemory-policy。
2.超时剔除:例如expire。
3.主动更新:开发控制生命周期

在这里插入图片描述
两条建议
1.低一致性:最大内存和淘汰策略
2.高一致性:超时剔除和主动更新结合,最大内存和淘汰策略兜底。

11-4 缓存粒度问题

在这里插入图片描述
缓存粒度控制-三个角度
1.通用性:全量属性更好。
2.占用空间:部分属性更好。
3.代码维护:表面上全量属性更好。

11-5 缓存穿透问题

在这里插入图片描述
原因
1.业务代码自身问题
2.恶意攻击、爬虫等等

如何发现
1.业务的相应时间
2.业务本身问题
3.相关指标:总调用数、缓存层命中数、存储层命中数

解决方法1-缓存空对象

在这里插入图片描述
两个问题
1.需要更多的键。
2. 存储层数据可能只是短期挂掉,缓存层数据置为空会导致 二者“短期”不一致。
在这里插入图片描述
代码中若 存储层中的数据为空 则设置在缓存中设为空,并且设置过期时间

解决方法2-布隆过滤器拦截

在这里插入图片描述
该方法更适用于较为固定的数据。

11-6 缓存雪崩优化

11-7 无底洞问题

问题描述:
2010年,Facebook有了3000个Memcache节点。
发现问题:“加”机器性能没能提升,反而下降。
http://highscalability.com/blog/2009/10/26/facebooks-memcached-multiget-hole-more-machines-more-capacit.html

问题关键点:

  1. 更多的机器!=更高的性能
  2. 批量接口需求(mget,mset等)
  3. 数据增长与水平扩展需求
    在这里插入图片描述
    优化IO的几种方法
    1.命令本身优化:例如慢查询keys、hgetall bigkey
    2.减少网络通信次数
    3.降低接入成本:例如客户端长连接/连接池、NIO等

四种批量优化的方法
1.串行mget
2.串行I0
3.并行I0
4.hash_tag

11-8 热点key的重建优化

在这里插入图片描述
三个目标和两个解决
1.三个目标:
减少重缓存的次数
数据尽可能一致
减少潜在危险

2.两个解决:
互斥锁(mutex key)
在这里插入图片描述
实例代码
在这里插入图片描述
永远不过期
1.缓存层面:没有设置过期时间(没有用expire)。
2.功能层面:为每个value添加逻辑过期时间,但发现超过逻辑过期时间后,会使用单独的线程去构建缓存。
在这里插入图片描述
代码示例:
在这里插入图片描述
两种方案比较:
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章