redis详解

长文警告,由于刚刚开始写博文,格式不太会更改,
原文为记事本整理,更没有字体了,
比较全面,有爱自取0.

REDIS概括
Redis介绍:
nosql.key-value键值对,可持久化,分布式,内存,缓存数据库

    缓存需要存在的特点:
    性能高;
    可用性高;
    分布式;

    Nosql:not only structured query language(不仅结构查询语言)
    概念:结构化数据库,非结构化数据库,关系型数据库,非关系型数据库
        非结构化数据包含结构化数据
        关系型数据库一定存储的是结构化数据
        非关系型数据库存储的可以是结构化数据,也可以是非结构化数据
    Redis是一个非关系型数据库(什么都能存)  

    Key-value键值对
    以键值来存储,值的结构可以千变万化,每一个不同的键值对应的内容
    都是非结构化数据的内容

    可以持久化:
        针对内存存储的一个保障性
        数据宕机回复:
        redis市场占有率高的重要原因,将内存数据在磁盘写出保存,宕机后内存数据消失
        重启服务,加载磁盘数据文件,保证数据的命中

    分布式:
        为什么key1放到第一个redis?分配逻辑表示将海量数据切分存储
        就是对key值进行计算分布操作的过程----数据分片

    缓存数据库:
        要想在工程项目中使用(controller-->service-->持久层)


    持久层缓存:
        减少数据库获取结果的封装,减少创建使用连接的时间;           

redis与memorycache
Ecache:很多数据库内存的缓存架构;mysql现在也在用它;性能比较低
MemoryCache:性能非常高;企业很多曾经使用的高级缓存架构;
缺点:不能将数据落地;当集群或者工程出现异常问题(宕机,人祸天灾),
内存数据全部丢失,会出现雪崩/缓存击穿(数据大量未命中)

    集群永不宕机(集群高可用)
    依赖外部的持久化:性能特别低

Redis:与memorycache伯仲之间的性能对比;支持线性扩容(5000个节点)

雪崩/缓存击穿
海量数据的访问请求,一旦发起,将会涌入系统,如果缓存数据可命中率高,数据库压力减小
可以提供对外正常的数据处理的能力,当缓存由于各种原因,造成大量数据未命中,
海量数据请求涌入数据库,造成数据库宕机—恢复重启—-海量请求未消失—宕机–重启;

Redis安装和启动

RedisApi命令
Value的数据存储的是非结构化数据,元素结构多种多样
redis根据业务需求定义了五种value的数据类型
String:字符串类型;
Hash:具有对象结构的value类型;
List:链表集合;有头有尾有中间
Set:集合
Zset:有序集合

String类型命令
    keys * 表示查询当前存储空间中所有存在的key

set get名:
    Set key value:将value的值作为数据存储到redis中
    Get key :将key键值对应的value从存储中获取出来

    Select[整数]默认情况下整数的取值区间是0-15
    当前的redis服务取用哪个数据分库;功能不常用

    exists[key值]:表示判断当前内存中是否由你要的key值存在;
    get也可以判断key值的存在
        :redis默认情况下value的数据可以支持到512M
        get命令判断,选读取数据,造成了浪费
    Dle[key]:将key值的数据从内存删除
        数据能否永久存在于redis?
        主动删除数据时人为操作,有人工成本;
        数据过时剔除的逻辑:
        1超时
        2自带的删除数据逻辑(LRU)lasted recent unused

    type:help
    type:查看当前数据的类型
    Help:查看命令的使用
    到官网查看command标签内容,

    save:将当前内存中数据保存到持久化文件中

    停止服务:redis-server shutdown
    内存数据确实丢失了,但是重新启动服务,加载指定的dump.rdb文件
    Flushall:将当前服务的所有数据清空(包括持久化文件中的数据)

    Flushdb:只清空当前分库的数据

    incr和decr:自增,自减 步数是1
    lncrby[key][步数] 
    decrby[key][步数]

    >append[key][value]:在存在的key对应的value数据中拼接传递的内容

    批量操作
    >mset mget 批量获取,批量写入;只能在本机的节点执行,不支持分布式

    >expire [key] second:设定当前key对应的数据超时时间(秒)

    >ttl[key] 查看倒计时
    超时之后,ttl的结果是什么? 删除数据,key值的超时时间变成-2
    -1表示永久数据

    精度超时
    >pexpire[key] 毫秒:显示的是秒数,代码客户端获取数据是毫秒

hash数据类型
面向对象的数据类型,key-value
String类型
key=user value={“id”:5,”name0”:”tony”}
hash类型
hash_key hash_value
id 5
name0 tony

Hset Hget:对hash数据类的设定和读取

hexists:判断属性是否存在

hdel:删除属性

hkeys hvals:只获取hash数据的key值对应的hashkey 或者hashvalue

hincrby[key][field]步数

hlen:判断当前hash类型数据的属性个数

List数据集合链
操作命令分左右,数据查看是上下

创建一个List链

lrange:查看从上到下的多个list元素数据

查看全部内容需要从0开始,到-1结束表示全部


rpush:从下插入数据链

lrem:从key对应的list中删除 count个相同value数据的元素;
    count可以大于0 小于0 等于0
    大于0表示从上到下删除 count个元素
    小于0表示从下到上删除 count个元素
    等于0 删除所有元素

lpop:从list的头部删除元素并且返回元素值

rpop:从list的尾部删除元素并返回元素值

proplpush:从第一个list的尾部移除元素,添加到第二个list的头部

以上这些命令,除了string以外,大部分的命令都是在redis中进行数据的变动或者计算
这样多种类型,配合多种数据计算的命令,可以在复杂业务逻辑中应对多种数据处理过程;

分布式高可用集群:
多实例部署
redis在同一台机器上要启动多个进程完成多实例部署;默认占用6379的情况下无法完成直接的三个实例启动
这个我们需要了解如何通过指定配置文件,将多实例部署在linux上

    默认的配置如何指定加载
    例如:默认配置6379端口,加载的dump是根目录的dump文件,在控制台打印日志..等等内容
    都可以利用启动命令redis-server[redis配置文件];
    redis.conf是根目录的模板配置文件

    步骤:修改配置文件完成第一个redis实例启动时加载的配置文件编辑
        同时学习需要了解的配置文件内容

vim linux文本编辑器
三种模式:
一般模式:可以调用快捷键命令,实现复制行,删除行
dd:表示删除当前光标所在行
vv:表示赋值光标所在行
p:表示将剪切板内容粘贴到光标所在行的下一行

    编辑模式:可以随意的输入任何文本信息;在一般模式下按快捷键i,o,a,都可以进入编辑模式esc退出到一般模式

    命令模式:可以执行保存文件,另存为,不保存退出等命令实现编辑后的决定
    在一般模式下输出:表示开启命令输入
    :q!不保存退出  :wq 保存退出


代码客户端
    数据分片的计算
        自定义计算逻辑
        hash取余计算方法
        jedis实现的hash一致性

高可用
    主从复制
    哨兵集群

jedis客户端代码
redis支持多种开发语言的客户端api
其中针对java有一套叫做jedis

1.jedis连接单点redis服务
利用jedis的对象连接redis创建客户端,从方法调用命令
(set,get,expire,incre,del)

jedis有没有api文档

2.模拟缓存逻辑在系统中的步骤
逻辑思路:请求到系统,执行代码,获取数据(从数据库获取,缓存)
if(缓存无数据){连接数据库查询数据;将查询结果存储到缓存}
else{返回数据}

3.自定义数据分片计算
当数据需要存储在不同的redis服务时,需要代码段完成数据分片存储的计算逻辑
模拟生成海量数据的key-value对,自定义对key值进行计算
完成分布式存储;(6379,6380,6381各自有一部分数据)

根据存储逻辑,完成相同的计算逻辑做读数据

分布式写入数据的计算逻辑,必须保持和分布式读取数据的计算逻辑一致
如果客户端代码按照上述逻辑完成分片计算,有什么问题存在?
1.数据量增长后:计算逻辑需要修改
2.key值变化取值区域后:计算逻辑需要修改
有没有一种一劳永逸的计算逻辑;

4.hash取余数据分片计算
散列算法在分片计算中,至关重要的地位,
其中一种叫做hash取余:hash计算 散列计算
java的所有内存对象都能够使用hash算法映射到一个int区间
-21亿-21亿;同一个对象(equal方法重写),对应的映射结果相同;
key值在自定义生成时,一批key的去值集合叫做key的取值区间;
利用散列hash可以做到任何key的数据类型都可以映射到整数区间;

hash取余的计算公式
key,hashCode()Integer.MAX_VALUE%n
n表示分片数量(服务进程数量,节点数量)

5.jedis数据分片
jedis本身也具有底层的分片计算逻辑;hash一致性

6.jedis的分片连接池
jedis提供性能更高的分片连接池对象,将jedis逻辑
引入框架,由框架来维护连接池对象;
可以使用伪service封装框架维护的连接池对象

7.springboot整合jedis
在框架中整合分片连接池,更好的完成缓存任务
体现其性能;

1.配置文件application收集连接池创建需要的信息连接节点
利用@Bean注解完成一个方法返回对象的框架管理,作用bean标签一样

创建返回的连接池对象,对象需要的信息数据,
想办法在application配置文件中读取过来                

2.编写Component类,或者Configuration,配合
@Value读取数据 ;@Bean获取框架管理的方法返回对象;

Hash一致性
散列算法在分布式中分片计算出现的问题
所有的散列算法都存在数据倾斜概念
假设1000条数据存储
node1:338;
node2:321;
node1:341;
少量数据可以接收;上亿条数据的存储需求,这一点点的数据倾斜会造成
其中某台机器承受大于其他服务器上千万条的数据,造成宕机
哈希取余的缺点
会造成服务器节点扩容,减少节点时的数据迁移量过大的问题

    如果使用hash取余算法完成分片计算,集群节点越多的情况下进行扩容删除操作
    数据未命中概率越大,雪崩越有可能发生

jedis实现了hash一致性的散列算法    
    介绍:1997年出现的一种算法,由麻省理工学院的大二学生在数学竞赛中发明的;
    引入了一个43亿的正整数区间;被称之为hash环;
    利用散列算法,将节点信息,key值同时映射到这个区间之内
    判断key与节点的对应关系
    一旦对应上,key值将保存到对应节点上

    当集群的节点越多的时候,扩容的时候迁移数据量就越小,未命中概率越小
    小到一定程度时,无需关心;

    解决数据平衡问题
    引入虚拟节点;不同实现hash一致性算法的语言,实现的过程不同jedis中,
    收集节点信息时,构造方法中有一个叫weight(权重值);权重值越大的节点保存的数据越多

    默认情况下,每一个真实节点对应160*weight个虚拟节点,默认weight=1;
    node1是真实节点
    node1:10.9.17.153:6379
    node1-1:10.9.17.153:6379#1
    node1-2:10.9.17.153:6379#2
    node1-3:10.9.17.153:6379#3

虚拟节点的信息字符串也会进行散列计算,投影到hash环上
jedis实现的hash一致性,如果想要更好的平衡存储的key值,可以在创建信息对象时,将weight值变大;

企业中将key值平衡性,将key值本身也做散列计算;

分布式集群的高可用
高可用需要做到对外提供功能redis节点,一旦宕机,不能影响集群的整体功能
不能数据大量未命中,需要采用主从复制为基础的高可用结构

主从复制
redis支持多个节点间建立主从关系,从节点实时备份主节点数据,而且支持多级,
多个节点的建立;
企业经验:最多做到二级主从,一主 六从;再多redis支持会不稳定,维护成本非常高

搭建redis主从结构
一主二从的redis主从

操作步骤
    1 准备主从节点的配置文件
    2 分别编辑配置文件
    3 分别启动对应文件的redis服务
    4 启动各自的redis服务
    5 调用客户端命令启动一主两从结构
    6 挂接完成返回ok查看主节点和从节点的replication变化内容

哨兵高可用集群
主从复制完成后,只能保证数据的多点备份;并不能提供高可用访问功能;

哨兵模式(sentinel):
启动哨兵进程后,将会自动监听管理配置时指定给他的主从结构中的主节点;
利用info命令查询主从的状态,rpc心跳机制监听主节点状态;
如果发现主节点宕机,会从记录的info信息中找到从节点,进行投票选举;
哨兵模式的哨兵进程也有多个,保证高可用
对主从的管理时,会对事件进行投票:例如 主节点宕机 过半选举,少数服从多数;
从节点替换也是事件

对于单个的哨兵主从高可用集群,只能负责存储数据分片中的一片,所以要做到分布式集群,
还需要相同结构的高可用集群负责其他的分片存储;
jedis代码联通时,可以连接哨兵集群,由哨兵集群转发数据传递给当前主从结构中的主节点;
代码客户端只要能连接哨兵,就无需关心主从结构的实际情况;

哨兵搭建:
安装哨兵集群;
操作步骤
1 修改启动哨兵的配置文件
2 启动哨兵进程,开启监听主从结构
3 测试
4 重新配置已经配好的哨兵集群步骤(重启似的)

哨兵的代码客户端
连接哨兵操作主从高可用集群

整理哨兵的框架整合思路
哨兵集群分布式思路
三个哨兵高可用集群的分布式代码

1.框架管理哨兵的连接池,创建内存三个连接池对象;
2.框架可以通过3个连接池获取所有的master信息;nodes
3.生成框架管理的分布式分片连接池;
4.如何在其中某个或某几个master替换之后动态修改分片连接池?
    利用异常机制;
    利用框架lnitializer接口:销毁框架管理对象后重新调用逻辑初始化
    利用框架Destroy接口:无效的对象,销毁

redis-cluster
概括
特点
结构
安装

集群功能测试
增加节点
主从节点添加
重新分片

核心概念/槽道

补充操作

哨兵高可用集群:
缺点:1 key值存储还是被动的
2 slave不变成master时,资源空闲

redis集群技术(redis-cluster)
介绍:3.0版本之后,针对前期版本的各种缺点和操作维护的不方便之处
退出了集群技术redis-cluster;

集群结构:
两两相连
特点
1.所有的redis节点彼此互联(两两之间的包括主从所有节点),
使用内部的二进制协议,来优化传输速度;
2.节点的事情,例如fail,是通过过半选举得出的结论,所有集群的主节点参与选举
(哨兵进程取消,但是机制整合到了主节点的功能当中);
3.客户端(jedis)与redis-cluster的联通不在是收集全部信息才能通信;
只需要至少连接一个节点,就可以实现数据的分布式存储;
(宏观感觉不需要客户端关心分片计算,实际上由于内部联通数据,单个节点连接后
客户端就可以获取所有数据)
4.redis-cluster把所有的主节点映射到[0-16383]区间对应的各个”槽道”号上
;各自主节点就维护了一个”槽道”号的分片区间
(master1–0-5461;master2-5462-9999),key值在传入任何一个节点时
进行哈希取模运算,key值对应一个”槽道”号,然后才能由负责这个”槽道”号的节点存储数据
key<–>slots<->节点;一旦想要调整槽道的管理区间,key值需要随之变动;
否则未命中,或者不可获取;

核心概念是"槽道"
图解:

理解"槽道"需要解决的两个问题:
    1.获取数据的节点如何判断当前key值的取模运算结果,是否在自己的管理范围内
    2.判断不归自己管时,如何获取正确的管理槽道的节点

    槽道的结构:
    16384位的二进制,位序列
    16384个元素的数组对象,共享数组;
二进制可以判断当前key值计算的映射结果是否归节点管理;
这里以8位二进制为例子,槽道是0-7的区间;每一位二进制的值(0,1),
如果是1表示这一位的"下标"对应的槽道号由当前节点管理,如果是0表示不管理;
8003节点管理的槽道号:0 1 2  8002节点管理  3 4

集群中:主节点的二进制各不相同;每一个下标号对应的二进制值,只有一个是1,剩下全是0;
所有主节点的二进制的或运算是16384位个1的二进制 位的与运算是0的二进制
    从节点的二进制全部相同,都是0;各自的从节点备份数据时,key-value,
    主节点的二进制一样备份;

测试代码:
    利用二进制的位移运算,获取其中每一个位对应的槽道号,当前位的二进制值
判断管理权的内容完成后,如果不归当前节点管理槽道,如何知道具体的槽道管理者是谁?

槽道的第二个部分:16384位的数组,可以解决这个问题
所有集群节点共享的一个数组,所有节点的数组信息相同;每个数组的元素
保存的内容有:当前元素下标对应槽道号的管理节点信息,保存槽道的状态
(正常,移出,导入,删除);map{槽道号:{key集合}}

以上两部分内容, 位序列,共享数组,就是集群槽道的真正逻辑

redis补充操作
重启集群
没有restart类似的重启集群的命令;
重启集群的目的:操作时的各种失误,导致集群失效;
杀掉所有进程
删掉文件(nodes_8000.conf:记录的是当前服务器的唯一一个集群的节点状态)
(dump8000.rdb也删除:为了防止启动其他新节点时,
读取原有dump的数据导致添加集群节点非空,失败)
可以调用原有的配置文件,启动redis服务,利用redis-tri.rb重建集群

手动搭建:调用集群

节点握手:
    登录任何启动的节点;>cluster meet ip port(ip 端口是其他节点信息)
    注意:跨服务器执行集群的搭建,需要登录时使用对外访问ip地址
初始化情况下,所有握手的节点都是master 8001属于有数据记录没清干净

添加其他节点到集群(槽道是没有分配的)

addslot执行完成后,当前节点和其他节点的共享数组发生变动,0号元素内容替换为8000
的节点信息,和其他所有节点的二进制,除了8000的第0位从0变成1,其他没变化
分配了一个槽道后,查看集群info状态,在16384个槽道全部分配完毕前

fail分配其他槽道的脚本,这里使用到shell脚本;例如如下脚本内容
vim 8000slots0_5461.sh
for i in {0..5461}; do redis-cli -h 10.9.17.153 -c -p 8000
cluster addslots $i;done
for i{5462..9999}; do redis-cli -h 10.9.17.153 -c -p 8000
cluster addslots $i;done(不要再文件中拷贝)
sh  8000slots0_5461.sh
9999-16383


cluster replicat ip 把本节点添加从节点
cluster nodes 查看状态

总结:redis-trib.rb 命令文件,就是利用ruby语言完成上述步骤的封装;
对外提供方便的调用命令

槽道的迁移(数据微调)
空槽道迁移
目标节点(8001)导入槽道(目标节点中二进制不便,数组当前槽道的状态发生变化)
cluster setslot 10923 importing 源节点id
在8001上登录,执行命令 10923是操作的槽道
importing将8001上的数组的10923元素中的槽道状态修改为导入importing
跟着的是源节点id 8002的id

    源节点(8002)导出槽道(源节点二进制不便,数组槽道状态变为导出)
        登录8002执行操作
        cluster setslot 10923 migrating 目标节点id
        通过cluster nodes观察到 8002的信息发生变化
    槽道的状态是正常,导入,导出,都不影响数据的插入
    数据微调的时候,集群不能对外提供服务;
    数据迁移工作,在维护内容属于重大维护事项;

    通知所有集群节点槽道迁移了()
    将所有的集群节点全部通知到,10923从现在开始,归8001所在
    cluster setslot 10923 node 目标id(8000二进制不变,数组变了)

    通知所有集群节点槽道迁移了(所有的节点,数组发生变化)

非空槽道迁移(reshard命令不支持)    
按照以上的内容,有数据的槽道可以迁移,但是数组保存着 map{槽道号:[keys]}
所以,要迁移非空槽道,需要同步的将数据keys一并迁移
        name存储在5798上,迁移5798
    目标节点导入槽道
        cluster setslot 5798 importing 源节点id
    源节点导出槽道
        cluster setslot 5798 migrating 目标节点id
    将槽道的数据迁移到目标节点
        确定当前槽道包含的所有key(5798)
            cluster getkeysinslot 5798 500
            查看5798上500个范围内的所有key;
        将获取的key值,进行迁移,从8001迁移到8002
        8001>migrate 目标节点ip 目标端口 "" 0 500 keys name
        "":表示key的匹配;可以使用正则(有待考证)
        0:表示迁移到目标节点的database(0-15)
        500:连接超时毫秒
        keys:标签确定迁移的key值名称
        name:key
        如果有多个key:keys name1 name2 name3 name4
        除了key-value执行迁移,map记录{槽道号:[keys]}一并迁移


    所有主节点通知更新数据(槽道迁移)
        cluster setslot 5798 node 目标id ++

SpringBoot框架整合jedisCluster
目的:spring容器启动时,自动创建维护jedisCluster对象,可以在代码中注入使用;
思路:
1 信息数据采集:配置文件application收集节点信息,
收集配置config对象的信息(maxTotal,maxidle,timeout)
2 信息注入Configuration对象:利用@Value收集数据,
在其他方法中使用value所在的私有属性,构造需要的对象
3 编辑方法,构造jedisCluster对象返回,利用@Bean使对象在框架中被维护
4 注入到任何容器的其他位置,Controller

application,properties
在原有基础上添加集群节点信息

Cluster

spring框架的思路:
clusterConfig



测试Controller是否高可用
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值