redis知识点总结

什么是redis

redis是一种基于键值对(key-value)数据库,其中value可以为string、hash、list、set、zset等多种数据结构,可以满足很多应用场景。还提供了键过期,发布订阅,事务,流水线,等附加功能。
流水线: Redis 的流水线功能允许客户端一次将多个命令请求发送给服务器,并将被执行的多个命令请求的结果在一个命令回复中全部返回给客户端,使用这个功能可以有效地减少客户端在执行多个命令时需要与服务器进行通信的次数。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因为是单线程需要排队处理任务,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

redis特性

1,速度快,数据放在内存中,官方给出的读写性能10万/S,与机器性能也有关
	1,数据放内存中是速度快的主要原因
	2,C语言实现,与操作系统距离近
	3,使用了单线程架构,预防多线程可能产生的竞争问题
2,键值对的数据结构服务器
3,丰富的功能:见上功能
4,简单稳定:单线程,同时使用了IO多路复用模型,采用epoll机制
5,持久化:发生断电或机器故障,数据可能会丢失,持久化到硬盘
6,主从复制:实现多个相同数据的redis副本
8,高可用和分布式:哨兵机制实现高可用,保证redis节点故障发现和自动转移
9,客户端语言多:java php python c c++ nodejs等

使用场景:

1,缓存:合理使用缓存加快数据访问速度,降低后端数据源压力
2,排行榜:按照热度排名,按照发布时间排行,主要用到列表和有序集合
3,计数器应用:视频网站播放数,网站浏览数,使用redis计数
4,社交网络:赞、踩、粉丝、下拉刷新
5,消息队列:发布和订阅

Redis基本通讯模型

执行过程:发送指令-〉执行命令-〉返回结果
执行命令:单线程执行,所有命令进入队列,按顺序执行,使用I/O多路复用解决I/O问题,后面有介绍(通过select/poll/epoll/kqueue这些I/O多路复用函数库,我们解决了一个线程处理多个连接的问题)
单线程快原因:纯内存访问, 非阻塞I/O(使用多路复用),单线程避免线程切换和竞争产生资源消耗
问题:如果某个命令执行,会造成其它命令的阻塞

redis数据结构

 1,字符串类型:
 	实际上可以是字符串(包括XML JSON),还有数字(整形 浮点数),二进制(图片 音频 视频),最大不能超过512MB
 	设值命令:set age 23 ex 10 //10秒后过期  px 10000 毫秒过期
       setnx name test  //不存在键name时,返回1设置成功;存在的话失败0
       set age 25 xx    //存在键age时,返回1成功
       场景:如果有多客户同时执行setnx,只有一个能设置成功,可做分布式锁
    获值命令:get age //存在则返回value, 不存在返回nil
    批量设值:mset country china city beijing
    批量获取:mget country city address //返回china  beigjin, address为nil
    计数:incr age //必须为整数自加1

 2,哈希hash:
 	是一个string类型的field和value的映射表,hash特适合用于存储对象,用序列化消耗性能,使用hash更合适。
 	hmset  user:1  name james  age  18;
 	HASH类型是稀疏,每个键可以有不同的filed,若用redis模拟做关系复杂查询开发因难,维护成本高。对于更新不多的情况下,可以使用序列化,对于VALUE值不大于64字节可以使用hash类型

 3,列表<list>:
 	用来存储多个有序的字符串,一个列表最多可存2的32次方减1个元素因为有序,可以通过索引下标获取元素或某个范围内元素列表,列表元素可以重复。
 	rpush james c b a //从右向左插入cba, 返回值3
 	lrange key start end //索引下标特点:从左到右为0到N-1

 4,集合<SET> :
	保存多元素,与列表不一样的是不允许有重复元素,且集合是无序,一个集合最多可存2的32次方减1个元素,除了支持增删改查,还支持集合交集、并集、差集;
	场景:用户标签,社交,查询有共同兴趣爱好的人,智能推荐。
	sadd user a b c//向user插入3个元素,返回3
	sadd user a b  //若再加入相同的元素,则重复无效,返回0
	smember user //获取user的所有元素,返回结果无序

  5,有序集合:
  	与集合有联系,不能有重复的成员。
  	场景:常用于排行榜,如视频网站需要对用户上传视频做排行榜,或点赞数。
  	zadd key score member [score member......]
  	查点赞数:
		zadd test:2 nx 100 james //新增一个集合
	排名:
		zadd user:3 200 james 120 mike 100 lee//先插入数据

心跳检测

客户端发送ping,服务端响应pong(发送三次回复三次)

redis相比memcached有哪些优势?

1,memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
2,redis的速度比memcached快很多,memcached是多线程需要使用CAS,消耗性能
3,redis可以持久化其数据,Memecache把数据全部存在内存之中
4,value的大小,redis最大可以达到1GB,而memcache只有1MB

事务

redis的事务是一种弱事务,开启事务是multi,提交事务是exec,但是lua脚本是原子性的,所以尽量多使用lua脚本,并且lua是将很多命令一起提交到redis队列中执行,所以避免的多条命令的执行去频繁进行网络请求的开销,所以效率很高,但是也要注意不要有太多的命令,否则会造成队列的阻塞,同时可以复用。

批量操作

可以使用redis原生的例如hmset之类的批量操作,但是只能对一种数据结构进行操作,所以推荐使用pipline管道,将数据在管道中进行拼接后一起提交到服务端,也可以使用lua脚本。使用pipline要注意手动提交事务。
注意:pipline管道没有原子性,原生的mset之类的批量操作命令有原子性,但是有局限性,只能是某种单一的操作,不能聚合批量。

持久化

Redis提供了两种持久化方式:RDB(默认)和AOF(zk中的持久化是undo和rado)
RDB:RDB持久化把当前进程数据生成快照(.rdb)文件保存到硬盘的过程,有手动触发和自动触发
    手动触发有save和bgsave两命令:
         save命令:阻塞当前Redis,直到RDB持久化过程完成为止,若内存实例比较大会造成长时间阻塞,线上环境不建议用它
         bgsave命令:redis进程执行fork操作创建子线程,由子线程完成持久化,阻塞时间很短(微秒级),是save的优化,在执行redis-cli shutdown关闭redis服务时,如果没有开启AOF持久化,自动执行bgsave;
         显然bgsave是对save的优化。
    优点:
	     1,压缩后的二进制文,适用于备份、全量复制,用于灾难恢复
         2,加载RDB恢复数据远快于AOF方式
	缺点:
   		 1,无法做到实时持久化,每次都要创建子进程,频繁操作成本过高
         2,保存后的二进制文件,存在老版本不兼容新版本rdb文件的问题

AOF:针对RDB不适合实时持久化,redis提供了AOF持久化方式来解决,同步的时候是redis另开一个线程进行执行。
	开启:redis.conf设置:appendonly yes  (默认不开启,为no)
	流程说明:
		 1,所有的写入命令(set hset)会append追加到aof_buf缓冲区中
         2,AOF缓冲区向硬盘做sync同步
         3,随着AOF文件越来越大,需定期对AOF文件rewrite重写,达到压缩
         4,当redis服务重启,可load加载AOF文件进行恢复
    AOF持久化流程:命令写入(append),文件同步(sync),文件重写(rewrite),重启加载(load)

比较:
	1、aof文件比rdb更新频率高,优先使用aof还原数据。
	2、aof比rdb更安全也更大
	3、rdb性能比aof好
	4、如果两个都配了优先加载AOF

redis重启时恢复加载AOF与RDB顺序及流程:
	1,当AOF和RDB文件同时存在时,优先加载
	2,若关闭了AOF,加载RDB文件
	3,加载AOF/RDB成功,redis重启成功
	4,AOF/RDB存在错误,redis启动失败并打印错误信息

RESP协议

RESP协议是redis的客户端和服务端之间通信的数据传输协议,RESP 的特点:实现简单、快速解析、可读性好
例如:*2 &3 abc &2 bc,表示有两组数据,分别长度为3和2

幂等操作

幂等操作:
	是其任意多次执行所产生的影响均与一次执行的影响相同(不用担心重复执行会对系统造成改变)
幂等性解决方案:
	1.数据库表加唯一索引:
		防止新增脏数据。比如对订单号进行加唯一索引,防止生成重复订单。如果不加索引的后果是:当根据订单号去支付,支付表生成两条重复的订单号,然后去支付宝、微信、易宝支付去支付,付款完成后,第三方异步回调接口,本地接口首先根据订单号查询实体,发现查询到两条,系统就会抛出异常。
	2.分布式锁
		利用redis,在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路
	3.token机制,防止重复提交
		(1). 数据提交前要向服务的申请token,token放到redis中,token有效时间 
		(2). 提交后后台校验token,同时删除token,生成新的token返回 

主从复制:

原理:
1,保存主节点信息
2,主从建立socket连接
3,发送ping命令
4,权限验证
5,同步数据集
6,命令持续复制

数据同步:
redis 2.8版本以上使用psync命令完成同步,过程分“全量”与“部分”复制
全量复制:一般用于初次复制场景(第一次建立SLAVE后全量)
部分复制:网络出现问题,从节占再次连主时,主节点补发缺少的数据,每次数据增加同步
心跳:主从有长连接心跳,主节点默认每10S向从节点发ping命令,repl-ping-slave-period控制发送频率

哨兵机制:

1,为什么要讲哨兵机制?
	A,我们学习了redis的主从复制,但如果说主节点出现问题不能提供服务,需要人工重新把从节点设为主节点,还要通知我们的应用程序更新了主节点的地址,这种处理方式不是科学的,耗时费事
	B,同时主节点的写能力是单机的,能力能限
	C,而且主节点是单机的,存储能力也有限
	
2,主从故障如何故障转移(不满足高可用):
    A,主节点(master)故障,从节点slave-1端执行 slaveof no one后变成新主节点
    B,其它的节点成为新主节点的从节点,并从新节点复制数据

3,哨兵机制(sentinel)的高可用:
  	原理:当主节点出现故障时,由redis sentinel自动完成故障发现和转移,并通知应用方,实现高可用性,整个过程只需要一个哨兵节点来完成,首先使用Raft算法(其实就是个选举算法)实现选举机制,选出一个哨兵节点来完成转移和通知。
  	哨兵有三个定时监控任务完成对各节点的发现和监控:
  		1,每个哨兵节点每10秒会向主节点和从节点发送info命令获取最拓扑结构图,哨兵配置时只要配置对主节点的监控即可,通过向主节点发送info,获取从节点的信息,并当有新的从节点加入时可以马上感知到;
  		2,每个哨兵节点每隔2秒会向redis数据节点的指定频道上发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其它哨兵节点的信息及对主节点的判断,其实就是通过消息publish和subscribe来完成的;
  		3,每隔1秒每个哨兵会向主节点、从节点及其余哨兵节点发送一次ping命令做一次心跳检测,这个也是哨兵用来判断节点是否正常的重要依据。

  	主观下线和客观下线:
		主观下线:刚我知道知道哨兵节点每隔1秒对主节点和从节点、其它哨兵节点发送ping做心跳检测,当这些心跳检测时间超过down-after-milliseconds时,哨兵节点则认为该节点错误或下线,这叫主观下线;这可能会存在错误的判断。
		客观下线:当主观下线的节点是主节点时,此时该哨兵3节点会通过指令sentinel is-masterdown-by-addr寻求其它哨兵节点对主节点的判断,当超过quorum(法定人数)个数,此时哨兵节点则认为该主节点确实有问题,这样就客观下线了,大部分哨兵节点都同意下线操作,也就说是客观下线

	领导者哨兵选举流程:
		 a,每个在线的哨兵节点都可以成为领导者,当它确认(比如哨兵3)主节点下线时,会向其它哨兵发is-master-down-by-addr命令,征求判断并要求将自己设置为领导者,由领导者处理故障转移;
		 b,当其它哨兵收到此命令时,可以同意或者拒绝它成为领导者;
		 c,如果哨兵3发现自己在选举的票数大于等于num(sentinels)/2+1时,将成为领导者,如果没有超过,继续选举。

redis集群:

RedisCluster是redis的分布式解决方案,在3.0版本后推出的方案,有效地解决了Redis分布式的需求,当遇到单机内存、并发等瓶颈时,可使用此方案来解决这些问题。
分区规则:
rediscluster采用了哈希分区的“虚拟槽分区”方式(哈希分区分节点取余、一致性哈希分区和虚拟槽分区)。
虚拟槽分区(slot):
RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]&16383)映射到0-16383槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据,哈希函数: Hash()=CRC16[key]&16383 按位与

   redis用虚拟槽分区原因:
	   1,解耦数据与节点关系
	   2,节点自身维护槽映射关系
	   3,分布式存储

redisCluster的缺陷:
a,键的批量操作支持有限,比如mset, mget,如果多个键映射在不同的槽,就不支持了
b,键事务支持有限,当多个key分布在不同节点时无法使用事务,同一节点是支持事务
c,键是数据分区的最小粒度,不能将一个很大的键值对映射到不同的节点
d,不支持多数据库,只有0,select 0
e,复制结构只支持单层结构,不支持树型结构。

节点之间的通信:	
	1,节点之间采用Gossip协议进行通信,Gossip协议就是指节点彼此之间不断通信交换信息,当主从角色变化或新增节点,彼此通过ping、pong进行通信知道全部节点的最新状态并达到集群同步
	2,Gossip协议:
		Gossip协议的主要职责就是信息交换,信息交换的载体就是节点之间彼此发送的Gossip消息,常用的Gossip消息有ping消息、pong消息、meet消息、fail消息
		meet消息:用于通知新节点加入,消息发送者通知接收者加入到当前集群,meet消息通信完后,接收节点会加入到集群中,并进行周期性ping pong交换
		ping消息:集群内交换最频繁的消息,集群内每个节点每秒向其它节点发ping消息,用于检测节点是在在线和状态信息,ping消息发送封装自身节点和其他节点的状态数据;
		pong消息,当接收到ping meet消息时,作为响应消息返回给发送方,用来确认正常通信,pong消息也封闭了自身状态数据;
		fail消息:当节点判定集群内的另一节点下线时,会向集群内广播一个fail消息。
	3,消息解析流程:
		所有消息格式为:消息头、消息体,消息头包含发送节点自身状态数据(比如节点ID、槽映射、节点角色、是否下线等),接收节点根据消息头可以获取到发送节点的相关数据。
	4,选择节点并发送ping消息:
		Gossip协议信息的交换机制具有天然的分布式特性,但ping、pong发送的频率很高,可以实时得到其它节点的状态数据,但频率高会加重带宽和计算能力,因此每次都会有目的性地选择一些节点; 但是节点选择过少又会影响故障判断的速度,redis集群的Gossip协议兼顾了这两者的优缺点。
	不难看出:节点选择的流程可以看出消息交换成本主要体现在发送消息的节点数量和每个消息携带的数据量

集群扩容:
这也是分布式存储最常见的需求,当我们存储不够用时,要考虑扩容
扩容步骤如下:
A,准备好新节点
B,加入集群,迁移槽和数据

故障转移:
redis集群实现了高可用,当集群内少量节点出现故障时,通过故障转移可以保证集群正常对外提供服务。当集群里某个节点出现了问题,redis集群内的节点通过ping、pong消息发现节点是否健康,是否有故障,其实主要环节也包括了 主观下线和客观下线;

故障恢复:
故障主节点下线后,如果下线节点的是主节点,则需要在它的从节点中选一个替换它,保证集群的高可用;

慢查询

可以通过slow-quey-log设置慢查询,慢查询是存放在一个队列中的。

单台Redis的存放数据必须比物理内存小

Redis 的数据全部放在内存带来了高速的性能,但是也带来一些不合理之处。比如一个中型网站有100万注册用户,如果这些资料要用Redis来存储,内存的容量必须能够容纳这100万用户。但是业务实际情况是100万用户只有5万活跃用户,1周来访问过1次的也只有15万用户,因此全部100万用户的数据都放在内存有不合理之处,RAM需要为冷数据买单。
这跟操作系统非常相似,操作系统所有应用访问的数据都在内存,但是如果物理内存容纳不下新的数据,操作系统会智能将部分长期没有访问的数据交换到磁盘,为新的应用留出空间。现代操作系统给应用提供的并不是物理内存,而是虚拟内存(Virtual Memory )的概念。
基于相同的考虑,Redis 2.0 也增加了VM特性。让Redis 数据容量突破了物理内存的限制。并实现了数据冷热分离。

不用get / set方式使用Redis

作为一个key / value 存在,很多开发者自然的使用set/get 方式来使用 Redis ,实际上这并不是最优化的使用方法。尤其在未启用VM 情况下,Redis 全部数据需要放入内存,节约内存尤其重要。假如一个key-value单元需要最小占用512字节,即使只存一个字节也占了512字节。这时候就有一个设计模式,可以把key复用,几个key-value放入一个key中,value再作为一个set存入,这样同样512字节就会存放10-100倍的容量。这就是为了节约内存,建议使用hashset而不是set/get的方式来使用Redis。

redis常见性能问题和解决方案:

1,Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
2,如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一
3,为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
4,尽量避免在压力很大的主库上增加从库
5,主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3…

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

MySQL里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据:

可以使用redis的数据淘汰策略,使用从数据集中挑选最近最少使用的数据淘汰的策略。
6种策略:
	voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
	volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
	volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
	allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
	allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
	no-enviction(驱逐):禁止驱逐数据
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值