redis缓存及集群

一、持久化数据库的缺点:

1、平常我们使用的关系型数据库有Mysql、Oracle以及SqlServer等,在开发的过程中,数据库通常都是通过web提供的数据库驱动来连接数据库进行curd操作。那么我们 日常使用的数据库的数据都存储存储在哪里呢?

以mysql为例子:打开mysql所在文件夹目录下的的data文件夹,如下所示:

 

也就是说,我们日常使用的关系型数据中的数据,全部存储在我们部署数据库的机器的硬盘中。一般我们的网站开发完成,上线之后,服务器的读写效率是网站运行速度的重要条件,当然还有服务器的带宽等,但是这些东西都可以通过硬件的更新升级来解决。其实与网站运行效率息息相关的东西,就是我们的------数据库。

2、提高数据库的效率的办法:

(1)sql语句的优化技术,sql语句写的处理效率比较高,数据库处理能力就会上去,而网站的数据处理能力也会快些。

(2)使用高并发处理、负载均衡和分布式数据库

(3)降低数据库的读写次数,引入缓存技术。

3、使用缓存减轻数据库的负载缓存就是在内存中存储的数据备份,当数据没有发生本质改变的时候,我们就不让数据的查询去数据库进行操作,而去内存中取数据,这样就大大降低了数据库的读写次数,而且从内存中读数据的速度比去数据库查询要快一些,这样同时又提高了效率。

二、redis

1、百度百科给出的定义:Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。(因为是C语言编写的,所以在linux安装的时候就很不友好、用户体验 差评哈哈哈哈哈哈大笑

2、使用redis作缓存的好处:

(1)性能:我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应

(2)并发:并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。

3、使用redis作缓存需要考虑的几个问题:

缓存和数据库双写一致性问题、缓存雪崩、缓存击穿、缓存穿透、热点key重建

(1)缓存雪崩:在同一时间大量缓存失效,导致数据库压力激增从而崩溃。

解决办法:将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

(2)缓存击穿:针对某一个非常“热点”的key,在它即将过期的那一个瞬间恰巧有大量的并发请求过来,这些请求发现缓存过期一般都会从DB加载数据并回到缓存,这个时候大并发的请求可能会瞬间把DB压垮。

(3)缓存穿透:缓存穿透是指查询一个根本不存在的数据,缓存层和存储层都不会命中。通常处于容错的考虑,如果从存储层查询不到数据则不会写入缓存层。缓存穿透将导致请求不存在的数据每次都要到存储层去在找,就失去了缓存保护后端存储的意义。 造成缓存穿透的原因主要有两个:自身业务代码或者数据出现问题和一些恶意攻击或爬虫造成大量空命中 

解决办法:对于缓存穿透,可以给不存在的数据缓存一个空对象,同时设置超时时间。如果在此期间缓存层和存储层的数据不一致,可使用消息系统或者其他操作剔除缓存中的空对象。

 

4、单线程的redis为什么这么快

纯内存操作、单线程操作,避免了频繁的上下文切换、采用了非阻塞I/O多路复用机制

说一下非阻塞I/O多路复用机制:只有单个线程,通过跟踪每个I/O流的状态,来管理多个I/O流。我们的redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/0多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。

5、redis的持久化

RDB:当数据库中的key-value值有进行相应的增删改时,每经过一段时间,对数据库进行一次快照,保存为dump.rdb文件,服务器每次重启时都会将dump.rdb里的数据读到redis中

配置RDB的方法:redis.conf文件

save 900 1              #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。

save 300 10            #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。

save 60 10000        #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

AOF:使用日志功能保存数据,默认AOF是关闭的

在Redis的配置文件中存在三种同步方式,它们分别是:

appendfsync always     #每次有数据修改发生时都会写入AOF文件。

appendfsync everysec  #每秒钟同步一次,该策略为AOF的缺省策略。(默认,但可修改)

appendfsync no          #从不同步。高效但是数据不会被持久化。

6、redis的过期策略以及内存淘汰机制

定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,惰性删除派上用场。也就是说当你每次获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制

# maxmemory-policy allkeys-lru

1)noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
2)allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。
3)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
4)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
5)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
6)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

7、redis集群(3.0之后的版本才可以搭建集群)

即使使用哨兵,此时的redis集群中的每个数据库依然存有集群中的所有数据,从而导致集群的总数据存储量受限于内存最小的数据库节点,形成木桶效应。

Redis3.0版的一大特性就是支持集群功能。集群的特点在于拥有和单机实例同样的性能,同时在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持。另外集群支持几乎所有的单机实例支持的命令,对于设计多键的命令,如果每个键都在同一个节点中,则可以正常支持,否则会提示错误。除此之外集群还有一个限制是只能使用默认的0号数据库,如果执行select切换数据库会发生错误。

哨兵和集群是两个独立的功能,但从特性来看哨兵可以是集群的子集,当不需要数据分片或者已经在客户端进行分片的场景下哨兵就已经足够用了。

(1)redis-cluster架构图

(2)redis-cluster投票容错:

(3)redis集群里面没有一个统一的入口,也就是说集群中每个节点都可以被客户端连接。集群内部的每个节点之间都是相互通信的(ping-pong机制),依据投票容错机制来检查集群的健康状态(如果超过半数的节点认为一个节点挂了,那它就挂了,上图中的红色节点)。如果挂了的节点有从节点,那么会将从节点扶正,这时候集群还可以继续提供服务。如果没有从节点,那么集群就不可用了。

架构细节:

A、所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。

B、节点的fail是通过集群中超过半数的节点检测失效时才生效。

C、集群是否可继续提供服务需要判断挂了的节点是否有从节点。

D、客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可

E、redis-cluster把所有的物理节点映射到[0-16383]slot,cluster 负责维护node<->slot<->value。

(4)redis集群中内置了 16384 个哈希槽,当需要在 redis集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。同理,当需要在redis集群中获取一个key的时候,先计算这个key在哪个槽,然后这个槽在哪台服务器上,最后在跳转到那台服务器上取出key即可。

(5)redis集群的搭建(关闭防火墙):

因为投票容错机制,redis集群中至少应该有三个节点。要保证集群的高可用,需要每个节点有一个备份机。redis集群至少需要6台服务器。可以搭建伪分布式。使用一台虚拟机运行6个redis实例。需要修改redis的端口号7001-7006

(6)获取与插槽对应的节点

实际上,当客户端向集群中的任意一个节点发送命令后,该命令会判断相应的键是否在当前节点中,如果在当前节点,会向单机实例一样处理该命令;如果键不在该节点中,就会返回一个MOVE重定向的请求,告诉客户端这个节点目前由哪个节点负责,然后客户端再将同样的请求向目标节点重新发送一次以获得结果。

相比单机实例,集群的命令重定向也增加了命令的请求次数,因此请求重定向对性能还是有点影响的。

为了解决这一个问题,当发现新的重定向请求时,客户端应该在重新向正确节点发送命令的同时,缓存插槽的路由信息,就是记录下当前插槽是由哪一个节点负责的。这样每次发起请求时,客户端首先计算属于哪一个插槽,然后根据路由的缓存判断插槽由哪一个节点负责。考虑到插槽总数比较少,缓存所有插槽的路由信息后,每次发起命令只发向正确的节点,从而到达和单机实例同样的性能。

(7)故障恢复

在一个集群中,每个节点都会定期向其他节点发送ping命令,并通过有没有收到回复来判断目标节点是否已经下线。具体来说,集群中的每一个节点每隔1秒钟就会随机选择5个节点,然后选择最久没有响应的节点发送ping命令。

如果一定时间内目标节点没有响应回复,则发起ping命令的节点会主观认为该节点已经下线。如果要在整个集群中的所有节点都认为某一个节点下线,需要一定数量的节点都认为这个节点疑似下线才可以,这一个具体的过程为:

A:一旦节点A认为节点B疑似下线,就会在集群中广播这个信息,所有其他节点收到消息后会记录下这一信息

B:当进群中某一节点C收到半数以上的节点认为B疑似下线,就会将B标记为下线,并且向集群中的其他节点广播这一个信息,从而使用B节点在整个集群中下线。

在集群中,如果一个主数据库下线,集群就会进行故障恢复将其中一个从数据库转变成主数据库来保证集群的完整。

选择扶正的从数据库:

A、发现其复制的主数据库下线的型数据库(A)向每个集群中的节点发送请求,要求对方选自己成为主数据库。

B、如果收到请求的节点没有选择其他人,则同意将A设置为主数据库

C、如果A发现有超过集群中节点总数一半的节点同意选自己成为主数据库,则A成功成为主数据库

D、当有多个从数据库同时参选主数据库,则会出现没有任何节点当选的可能,此时每个参选节点等待一个随机事件重新发起参选请求,进行下一轮的选举,直到选举成功。

当某一个数据库当选为主数据库时,会通过命令salveof no one将自己转换为主数据库,并将旧的主数据库的插槽转换给自己负责。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值