reids解析
redis简介
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
redis作为缓存,如何添加?
数据库缓存
执行的过程包括sql,组织查询结果resultSet
根据sql可以创建缓存,存储已经查过的resultset,节省了
资源的调度重组resultSet
持久层缓存
减少从数据库获取的结果转化成对象的过程,缓存存在直接调用其中
保存的对象结果;
业务层缓存
减少调用层次
控制层缓存
较少调用层次
问题:可不可以过多的使用缓存?
缓存是占用内存空间的,过多的缓存插入,容易造成数据的冗余
在内存不够时,清空逻辑会交叉导致数据失效
结论缓存引入的最终目的:
1 减少数据库的访问压力
2 减少网络传输
3 减少封装层次
问题:如果在缓存服务器宕机后,无法进行数据恢复/没有解决数据重新加载的问题,会导致“雪崩”/“缓存击穿”
雪崩/缓存击穿
海量用户访问请求涌入,一旦缓存失效(宕机数据丢失);所有的访问
涌入数据库;数据库无法承受海量数据的查询,导致数据库服务器宕机;
重启数据库,请求查询没消失,数据库--宕机--重启循环,导致系统崩溃
解决雪崩:
1 缓存用不宕机;启动集群,永远让集群中的一部分起作用
2 缓存技术必须可以恢复数据,持久化
redis分布式
分布式,nosql,可以持久化,内存,数据库
分布式:数据被划分
nosql:not only sequence query language
不仅仅支持关系型数据--结构化的数据
还支持非关系型数据--非结构化数据
要完成数据的分片存储,需要至少多个redis实例
启动多个redis实例
前面的单个redis节点实例的启动时默认配置
端口号6379
配置文件
/redis根目录/redis.conf
配置文件的修改内容
p61 bind 用#注释掉
p80 保护模式不启动
p84 6379是默认端口(要启动其他的redis实例需要修改端口
p105 当客户端空闲时间一小时,就会自动断开连接,0秒表示
不启用超时配置
p128 daemonize 设置成yes让redis服务器启动有守护进程管理
(后台执行)
p150 对应不同的redis实例,pid的文件名称需要和端口同名
save 900(秒) 1(变动的数据条数)
当900以内,至少有1条数据变动,看是flush保存数据到文件
save 300 10
300秒以内至少10条数据变动,保存文件
save 60 10000
启动第二和第三个redis实例
redis-server redis.conf(指定启动文件)
需要第二个实例的配置文件
需要第三个实例的配置文件
拷贝redis.conf,用redis6380.conf,redis6381.conf
将拷贝的文件中只修改与端口有关内容
port
pid文件
6381的略
启动另外两个节点
#redis-server redis6380.conf
#redis-server redis6381.conf
#ps -ef|grep redis
指定端口登录客户端redis-cli -p [端口号]
#redis-cli -p 6380
#redis-cli -p 6381
6380和6381会共享6379的dump.db文件
所以不同的节点实例在同一个机器上运行时,可以修改dump.db
指定端口文件;
三个节点,怎么分布式保存数据?
数据来源:代码的逻辑执行
如何使用代码来操作redis执行分布式的数据存储过程?
引出了Jedis客户端
jedis
测试jedis控制redis的命令功能
需要导入jedis包
自定义分片
准备数据:
葵花宝典A,B,C三部分数据
将三部分数据分别存储到redis 6379 6380 6381
哈希取余
利用hash的散列特性,可以处理海量非结构化数据的散列分布的分片计算
代码
jedis分片
没有在分片时使用哈希取余,hash一致性
经过代码发现,一般的自定义分片逻辑计算无法做到散列
不散列无法均衡
jedis池
HASH一致性
作为散列算法
考虑哈西取余的问题
1 容易产生大规模的数据倾斜(散列必定倾斜)
hash一致性一定程度的解决了数据倾斜;
2 哈希取余算法,导致数据迁移量过大
当redis集群数量进行增加减少的时候,哈希取余算法中的n变化了
由于n的变化,数据命中变化量非常大,需要迁移的数据量非常大,
jedis中引入另外一种hash散列算法--hash一致性
1997麻省理工学生发明;引入一个2^32-1(43亿)整数环,
把节点使用ip+端口做哈希散列计算,得到43亿中一个值,投射到环中
将所有的数据ke y进行哈希散列计算,得到43亿中的一个
node1,2,3个节点启动着redis
数据分别是key1,2,3,4
根据hash散列算法都投射到一个整数上
顺时针寻找最近节点的映射规则,将key值进行存放
key1,2存储在node1
key3存储在node2
key4存储在node3
当增加删除节点时,迁移量有何变化?
增加node4,根据散列得到43亿中一个整数,投射到环上
根据顺时针寻找最近节点存储的原则,只需要迁移key4
而且可以判断,原节点数量越多,迁移量越小
节点删除,将node2删除,迁移key3
解决数据平衡性
单独的使用节点的ip+端口做映射,毕竟节点数量是有限的
有可能在映射时的各自分布位置并不平均,导致数据偏移量非常大
解决数据的平衡性引入虚拟节点
node1的ip是192.168.40.156
node2的ip是192.168.40.157
各自引入2个虚拟节点(虚拟节点的数量是非常大的)
node1-1=hash(192.168.40.156#1)
node1-2=hash(192.168.40.156#2)
node2-1=hash(192.168.40.157#1)
node2-2=hash(192.168.40.157#2)
每一个虚拟节点在哈希环上也会接收顺时针寻找最近节点的key们
通过增加节点数量(虚拟的),完成数据的映射平衡
凡是投影到node1-1,node1-2的key,都会中真实存储在node1中
所以虚拟节点越多平衡性越好
hash取余数据分片
主从复制+哨兵集群
当前redis结构可用性非常低,当其中某个节点宕机时,数据不可查
解决不可用需要引入高可用的结构
引入三台机器,将主节点的数据全部复制
主从复制,数据备份
当主节点宕机后,如果从节点能够顶替主节点接收请求,这种结构就
叫做高可用,分布式架构中,必不可少高可用特性
AP理论
C: consistency(一致性)
A: avalibility(可用性)
P: Partition(分区)-tolerence to partition(分区容忍度)
随着数据量存储增长需求,业务的多元化,分布式结构必不可少,CAP理论
是分布始终的公认基础理论之一
分区:一个分布式系统中,多个系统组成网络本来应该是互通的,但是可能因为
某种原因导致某两个或几个节点间的数据通信断开;导致整个系统被分割成了
几个数据区域;(分区是常态);
当分区出现时,数据的修改就需要考虑一致性;
一致性:数据在某个查看的时间点上保持整体一致
如果在修改数据时,对于查看数据的客户端要求数据一致,必须加锁,实现整体数据一致性
如果在数据修改时,对于查看数据的客户端不要求数据一致;不是数据一致性的体现
分区容忍度:如果对数据一致性要求高的话,分区容忍度高,一致性需要执行(加锁)
如果对数据一致性要求低,分区容忍度低
如果要求数据一致性高的(加锁),查看数据的人在一段时间内无法进行查看了
可用性:请求在一定时间段内都有回应(返回的数据)
分区容忍度高--数据一致性要求高--可用性降低
CP理论
分区容忍度低--数据一致性要求低--可用性高
AP理论
CAP中分区是常态,不可避免,只能满足剩下两个理论中的一条与分区理论共存
不可能达到三种同时共存;
分区导致一致性的要求,要求高导致可用性低,要求低导致可用性高;
主从结构:
redis可以提供主从复制的结构,
master-slave,redis提供的主从结构可以多级复制
主节点的数据实时同步到从节点,当搭建完成测试主从数据是否一致
修改,新增,删除一致
哨兵模式
测试主从结构的高可用
把主节点kill掉,看看某一个从节点能否主动担任主节点的功能,并且挂接另
一个从节点继续完成主从复制;
在主节点6382中执行操作
观察从节点状态
发现主从角色并没有转变,高可用未启动
redis中引入哨兵模式
哨兵是redis启动的进程,一个哨兵进程可以挂载一个主从的结构,来管理当前主从的高可用,多个哨兵进程可以挂载多个主从结构,多个哨兵可以挂载一个主从
哨兵进程通过连接主从执行info命令,判断当前主从结构是否正常,当发现主节点宕机,将会启动内部逻辑,将从节点中的slave-priority数值较高的节点启动替换主节点,将其他的从节点挂接到新的主节点上完成高可用主从替换
当哨兵集群启动后,整体的架构就是高可用的最终模式
哨兵-主从复制的集群最终模式
redis集群
哨兵集群的缺点:
1横向扩展不方便;一旦扩展,无论代码结构多么操作简单,都需要修改
哨兵集群和普通分布式redis集群都支持横向扩展
扩展后需要对代码进行重新编辑--redis集群解决了在横向扩展后,
代码无需变动
2 散列分布式算法是hash一致性;无论多少的数据迁移,都会造成调用代码
逻辑在扩展集群和收缩集群式做数据迁移
hash一致性虽然使数据迁移量得到缩小,但是每当扩展集群结构时,
如何迁移数据?
迁移数据需要额外编写代码
重新计算key的映射,将新的映射关系确定后,将key-value存到
对应新的节点
--redis集群可以不需要代码的数据迁移,手动迁移也可以,而且比代码执行
效率和方便程度高非常多;
特点:
集群中无需引入哨兵,集群的技术默认管理主从高可用结构
集群中的每个节点(redis实例)都两两相通,达到数据的传递高效
从节点也是整个集群中两两相通的成员之一;
引入了一个虚拟槽道的概念
和hash一致性不一样,不在将数据投射到43亿环上
而是使用一个0-16383号的槽道概念来对应key的映射
redis集群架构
对于客户端,连接redis集群无需配置全部ip和端口
最少配置一个就可以,分布式不是代码维护而是
集群内部管理数据分布;
内部数据key-value的传递过程是根据一个
0-16383(16384)槽道
内部的数据重定向(data redirect)
这样一个结构可以改变扩容和收缩时修改代码配置的问题;
第一个问题,根据学习redis集群的架构,在redis集群中可以解决
迁移工作为什么不需要在集群中使用代码完成?
在集群中所有的key真正映射关系和redis节点本身无关,只和槽道号有关,需要数据迁移时,不能直接对key-value对数据操作,而是将槽道进行重新分配(reshard)
集群中的所有数据将会根据重新计算的槽道管理内容进行重新转发保存(迁移的过程类似于修改数据加锁的过程,不能再迁移时进行数据操作)
重新分配槽道后,所有对应当前迁移这些槽道号的key-value数据对都会根据槽道的重新分配进行转发存储
1 计算槽道号
2 管理槽道号变化
3 重新计算key哈希取模
在redis集群中,可以调用迁移命令来reshard数据槽道号;所以无需代码客户端调用程序重新分配数据;
问题:
每一个节点如何知道我自己的管理槽道到底是哪些?
如果自己不管理,如何获取共享信息将数据转发?
每一个节点都维护2个信息,一个是16384位的位序列
16384bit的二进制
每个节点都维护一个16384个元素的数组
要知道本节点维护的槽道号,只需要访问计算本节点中这个16384位的位序列二进制
在集群中所有节点共享一个16384个元素的数组
数组元素保存节点信息;集群中每个节点的数组信息一致
reshard分片过程中,位序列和数组的变化
位序列先计算,变化,每一个变动槽道号的master节点的位序列;
例子;7001 400-500;然后将这101个槽道挪走了挪到7002
位序列变化 400-500节点从1编程0;数组信息 400-500的元素清空;
7002 接收400-500;然后位序列中的400-500位从0变成1;将共享数组的400-500元素赋值,自己的值
主从从复制,主宕从顶的特点;
主从复制;复制主节点的key-value数据
位序列为0
共享数组也存在从节点;
主从替换;7001主,7003从
位序列不一样,数据一样,数组一样;
7003顶替的过程;将数组进行分析,是7001的获取下标,计算位序列;根据位序列修改数组,将位序列是1的下标对应更新数组元素;数组同步复制;
数据的重新计算:
1 主从替换时,数据完全不用动
2 reshard过程完成后,所有key重新计算,根据转发逻辑,改转发的转发,改保留的保留