Redis

Redis

Redis采用的是基于内存的采用的是单进程单线程模型的KV数据库

Key-value进行存储

Value类型较多:String、list、set、zset(有序列表)、HASH(可以理解为Map,PS:HASH类型定义:1、由field和关联的value组成的键值对; 2、field和value是字符串类型; 3、一个hash中最多包含2^32-1个键值对)

redis相对关系型数据库支持存过期

redis持久化 RDB持久化 和 AOF持久化 RDB持久化:将redis服务的键值对保存到RDB文件中 AOF持久化:通过保存redis服务器所执行的写命令来记录数据库状态,所保存的是AOF文件

save命令和bgsave命令 当save命令执行时,redis服务器会被阻塞,所以当save命令正在执行时,客户端发送的所有命令请求都会被阻塞。 bgsave命令则由子进程执行保存工作,其不会产生服务器阻塞。 以下为设置保存策略: save 900 1 服务器在900秒内,对redis数据库进行了至少1次修改,bgsave命令会被执行 save 300 10 save 60 10000

redis会采用以上两种策略的融合,在满足rdb 保存策略的按照rdb进行持久化,而不满足的中间过程,则以aof进行保存。

redis事务:不能保证一致性,即多条命令中有失败的,也无法将所有命令回滚

--------------------------------------------------redis的三种集群方式---------------------------------------------------------- redis有三种集群方式:主从复制,哨兵模式和集群。

1.主从复制

主从复制原理:

从服务器连接主服务器,发送SYNC命令; 主服务器接收到SYNC命令后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令; 主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令; 从服务器收到快照文件后丢弃所有旧数据,载入收到的快照; 主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令; 从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;(从服务器初始化完成) 主服务器每执行一个写命令就会向从服务器发送相同的写命令,从服务器接收并执行收到的写命令(从服务器初始化完成后的操作) 主从复制优缺点:

优点:

支持主从复制,主机会自动将数据同步到从机,可以进行读写分离 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成 Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。 Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。 Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据 缺点:

Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性。 Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

注意,如果采用了主从架构,那么建议必须开启 master node 的持久化,不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制, slave node 的数据也丢了。


2.哨兵模式

当主服务器中断服务后,可以将一个从服务器升级为主服务器,以便继续提供服务,但是这个过程需要人工手动来操作。 为此,Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。

哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个。

(1)监控主服务器和从服务器是否正常运行。 
(2)主服务器出现故障时自动将从服务器转换为主服务器。

哨兵的工作方式

每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN) 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN) 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。 哨兵模式的优缺点

配置哨兵监控一个系统时,只需要配置其监控主数据库即可,哨兵会自动发现所有复制该主数据库的从数据库 这里之所以只需要连接主节点,是因为通过主节点的info命令,获取从节点信息,从而和从节点也建立连接,同时也能通过主节点的info信息知道新增从节点的信息。 哨兵启动后,会与主数据库建立两条连接。 1.订阅主数据库sentinel:hello频道以获取同样监控该数据库的哨兵节点信息 2.定期向主数据库发送info命令,获取主数据库本身的信息。

和主数据库建立连接后会定时执行以下三个操作: 每隔10s向主数据库和从数据库发送info命令 每隔2s向主数据里和从数据库的sentinel:hello频道发送自己的信息。 每隔1s向所有数据库节点和所有哨兵节点发送ping命令。 第一条操作的作用是获取当前数据库信息,比如发现新增从节点时,会建立连接,并加入到监控列表中,当主从数据库的角色发生变化进行信息更新。 第二条操作的作用是将自己的监控数据和哨兵分享,发送的内容为: <哨兵地址>,<哨兵端口>,<哨兵运行id>,<哨兵配置版本>,<主数据库名字>,<主数据库地址>,<主数据库端口>,<主数据库配置版本>,每个哨兵会订阅数据库的sentinel:hello频道,当其他哨兵收到消息后,会判断该哨兵是不是新的哨兵,如果是则将其加入哨兵列表,并建立连接。

第三条操作的作用是监控节点是否存活。该时间间隔有down-after-millisecond实现,当该值小于1s时,哨兵会按照设定的值发送ping,当大于1s时,哨兵会间隔1s发送ping命令。

优点:

哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。 主从可以自动切换,系统更健壮,可用性更高。 缺点:

Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。


3.Redis-Cluster集群

redis的哨兵模式基本已经可以实现高可用,读写分离 ,但是在这种模式下每台redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了cluster模式,实现的redis的分布式存储,也就是说每台redis节点上存储不同的内容。

Redis-Cluster采用无中心结构,它的特点如下:

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

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

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

集群至少需要3主3从,且每个实例使用不同的配置文件,主从不用配置,集群会自己选。

工作方式:(当存取的key来时候,对其进行算法加hash计算找到对应redis节点进行存取操作)

在redis的每一个节点上,都有这么两个东西,一个是插槽(slot),它的的取值范围是:0-16383。还有一个就是cluster,可以理解为是一个集群管理的插件。当我们的存取的key到达的时候,redis会根据crc16的算法得出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,通过这个值,去找到对应的插槽所对应的节点,然后直接自动跳转到这个对应的节点上进行存取操作。

为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

redis cluster 架构下,每个 redis 要放开两个端口号(6379和16379),16379 端口号是用来进行节点间通信的,也就是 cluster bus 的东西,cluster bus 的通信,用来进行故障检测、配置更新、故障转移授权。

优点

无中心架构,支持动态扩容,对业务透明 具备Sentinel的监控和自动Failover(故障转移)能力 客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可 高性能,客户端直连redis服务,免去了proxy代理的损耗 缺点

运维也很复杂,数据迁移需要人工干预 只能使用0号数据库 不支持批量操作(pipeline管道操作) 分布式逻辑和存储模块耦合等

-------------------------------- https://www.cnblogs.com/51life/p/10233340.html -----------------------------------------

 

Redis发布订阅和应用场景

Redis 发布订阅(pub/sub)是一种消息通信模式,可以用于消息的传输,Redis的发布订阅机制包括三个部分,发布者,订阅者和Channel。适宜做在线聊天、消息推送等。

发布者和订阅者都是Redis客户端,Channel则为Redis服务器端,发布者将消息发送到某个的频道,订阅了这个频道的订阅者就能接收到这条消息,客户端可以订阅任意数量的频道。

看到发布订阅的特性,用来做一个简单的实时聊天系统再适合不过了。这是其中之一,当然这样的东西,我们开发中很少涉及到。再举一个常用的,在我们的分布式架构中,常常会遇到读写分离的场景,在写入的过程中,就可以使用redis发布订阅,使得写入值及时发布到各个读的程序中,就保证数据的完整一致性。再比如,在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们拉。总之场景很多,需要去挖掘。 这一功能最明显的用法就是构建实时消息系统,比如普通的即时聊天,群聊等功能。 简单的应用场景的话, 以门户网站为例, 当编辑更新了某推荐板块的内容后: CMS发布清除缓存的消息到channel (推送者推送消息) 门户网站的缓存系统通过channel收到清除缓存的消息 (订阅者收到消息),更新了推荐板块的缓存

前端启动的命令: [root@itheima bin]# ./redis-server 前端启动的关闭: 强制关闭:Ctrl+c 正常关闭:[root@itheima bin]# ./redis-cli shutdown 后端启动redis: [root@itheima bin]# ./redis-server redis.conf 关闭后端启动的方式: 强制关闭:[root@itheima bin]# kill -9 5071 正常关闭:[root@itheima bin]# ./redis-cli shutdown 后端启动与前端启动的一个重要差别,后端启动会读取redis.conf文件

Redis 的并发竞争问题如何解决,了解 Redis 事务的 CAS 操作吗。

Redis为单进程单线程模式,采用队列模式将并发访问变为串行访问。Redis本身没有锁的概念,Redis对于多个客户端连接并不存在竞争,但是在Jedis客户端对Redis进行并发访问时会发生连接超时、数据转换错误、阻塞、客户端关闭连接等问题,这些问题均是由于客户端连接混乱造成。对此有2种解决方法:

1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。

2.服务器角度,利用setnx实现锁。

MULTI,EXEC,DISCARD,WATCH 四个命令是 Redis 事务的四个基础命令。其中: MULTI,告诉 Redis 服务器开启一个事务。注意,只是开启,而不是执行。Redis 允许一个客户端不间断执行多条命令:发送 MULTI 后,用户键入多条命令;再发送 EXEC 即可不间断执行之前输入的多条命令。因为,Redis 是单进程单线的工作模式,因此多条命令的执行是不会被中断的。Redis 服务器收到来自客户端的 MULTI 命令后,为客户端保存一个命令队列结构体,直到收到 EXEC 后才开始执行命令队列中的命令。

EXEC,告诉 Redis 开始执行事务

DISCARD,告诉 Redis 取消事务

WATCH,监视某一个键值对,它的作用是在事务执行之前如果监视的键值被修改,事务会被取消。Redis 的官方文档上说,WATCH 命令是为了让 Redis 拥有 check-and-set(CAS) 的特性。CAS 的意思是,一个客户端在修改某个值之前,要检测它是否更改;如果没有更改,修改操作才能成功。

redis主从复制下哨兵模式---选举原理

当redis集群的主节点故障时,Sentinel集群将从剩余的从节点中选举一个新的主节点,有以下步骤:

  1. 故障节点主观下线

  2. 故障节点客观下线

  3. Sentinel集群选举Leader

  4. Sentinel Leader决定新主节点

当Sentinel集群选举出Sentinel Leader后,由Sentinel Leader从redis从节点中选择一个redis节点作为主节点

 

 

分片(分区)(shard)

Redis是单线程的,如何提高多核CPU的利用率?

可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(分区)(shard)。

分区是分割数据到多个Redis实例的处理过程,因此每个实例只保存key的一个子集。

  如果只使用一个redis实例时,其中保存了服务器中全部的缓存数据,这样会有很大风险,如果单台redis服务宕机了将会影响到整个服务。解决的方法就是我们可以采用分片/分区的技术,将原来一台服务器维护的整个缓存,现在换为由多台服务器共同维护内存空间。

Redis分区有两个主要目标:

  1. 它允许更大的数据库,用许多计算机的内存总和。如果不进行分区,你将会受限于单台计算机的内存。

  2. 它允许将计算能力扩展到多核和多台计算机,将网络带宽扩展到多台计算机和网络适配器。

关于redis的安装参照上一篇,默认安装好了redis.

  思路:采用在一台主机上实现分片的方式,所以只需要在该主机上配置启动三台redis的实例即可。因为redis默认使用的端口号为6379,所以这里我们分别使用6379、6380以及6381三个端口来实现。

img

分区的不足:

  1. 分区是多台redis共同作用的,如果其中一台出现了宕机现象,则整个分区都将不能使用,虽然是在一定程度上缓减了内存的压力,但是没有实现高可用。

  2. 涉及多个key的操作通常是不被支持的。举例来说,当两个set映射到不同的redis实例上时,你就不能对这两个set执行交集操作。

  3. 涉及多个key的redis事务不能使用。

  4. 当使用分区时,数据处理较为复杂,比如你需要处理多个rdb/aof文件,并且从多个实例和主机备份持久化文件。

  高可用的解决方案:可以采用哨兵机制实现主从复制从而实现高可用。

你知道有哪些Redis分区实现方案?

  • 客户端分区就是在客户端就已经决定数据会被存储到哪个redis节点或者从哪个redis节点读取。大多数客户端已经实现了客户端分区。

  • 代理分区 意味着客户端将请求发送给代理,然后代理决定去哪个节点写数据或者读数据。代理根据分区规则决定请求哪些Redis实例,然后根据Redis的响应结果返回给客户端。redis和memcached的一种代理实现就是Twemproxy

  • 查询路由(Query routing) 的意思是客户端随机地请求任意一个redis实例,然后由Redis将请求转发给正确的Redis节点。Redis Cluster实现了一种混合形式的查询路由,但并不是直接将请求从一个redis节点转发到另一个redis节点,而是在客户端的帮助下直接redirected到正确的redis节点。

分布式Redis是前期做还是后期规模上来了再做好?为什么? 既然Redis是如此的轻量(单实例只使用1M内存),为防止以后的扩容,最好的办法就是一开始就启动较多实例。即便你只有 一台服务器,你也可以一开始就让Redis以分布式的方式运行,使用分区,在同一台服务器上启动多个实例。

一开始就多设置几个Redis实例,例如32或者64个实例,对大多数用户来说这操作起来可能比较麻烦,但是从长久来看做这点牺牲是值得的。

这样的话,当你的数据不断增长,需要更多的Redis服务器时,你需要做的就是仅仅将Redis实例从一台服务迁移到另外一台服务器而已(而不用考虑重新分区的问题)。一旦你添加了另一台服务器,你需要将你一半的Redis实例从第一台机器迁移到第二台机器。

缓存热点key 缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端DB压垮。

解决方案

对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询

缓存雪崩

缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案

缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。

缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都落到数据库上,造成数据库短时间内承受大量请求而崩掉。

解决方案

接口层增加校验,如用户鉴权校验,id做基础校验,id<=0的直接拦截; 从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value对写为key-null,缓存有效时间可以设置短点,如30秒(设置太长会导致正常情况也没法使用)。这样可以防止攻击用户反复用同一个id暴力攻击 采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力

附加

对于空间的利用到达了一种极致,那就是Bitmap和布隆过滤器(Bloom Filter)。 Bitmap: 典型的就是哈希表 缺点是,Bitmap对于每个元素只能记录1bit信息,如果还想完成额外的功能,恐怕只能靠牺牲更多的空间、时间来完成了。

布隆过滤器(推荐)

就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。 它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。 Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。 Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。 Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。

缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

解决方案

设置热点数据永远不过期。 加互斥锁,互斥锁

缓存预热

缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,先查询数据库,然后再将数据缓存的问题!用户直接查询事先被预热的缓存数据!

解决方案

  • 直接写个缓存刷新页面,上线时手工操作一下;

  • 数据量不大,可以在项目启动的时候自动进行加载;

  • 定时刷新缓存;

缓存降级

当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。系统可以根据一些关键数据进行自动降级,也可以配置开关实现人工降级。

缓存降级的最终目的是保证核心服务可用,即使是有损的。而且有些服务是无法降级的(如加入购物车、结算)。

在进行降级之前要对系统进行梳理,看看系统是不是可以丢卒保帅;从而梳理出哪些必须誓死保护,哪些可降级;比如可以参考日志级别设置预案:

  1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;

  2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送告警;

  3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级;

  4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级。

服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据,可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值