redis使用总结

redis总结

为什么选择使用redis

传统的关系型数据库如mysql已经不能适用所有的场景,比如秒杀的库存扣减,很容易把数据库打崩,所以需要引入缓存中间件,目前市面上比较常用的缓存中间件有redis和memcached,考虑优缺点,选择了redis。

redis有哪些数据结构,以及应用场景

string:这是最简单的类型,就是普通的 set 和 get,做简单的 KV 缓存。计数器。共享用户Session:用户重新刷新一次界面,可能需要访问一下数据进行重新登录,或者访问页面缓存Cookie,但是可以利用Redis将用户的Session集中管理,在这种模式只需要保证Redis的高可用,每次用户Session的更新和获取都可以快速完成。大大提高效率。

hash:这个是类似 Map 的一种结构,这个一般就是可以将结构化的数据。商品对象可能里面就包含了很多属性,其中也有对象。

list:有序列表,存储一些列表型的数据结构,类似粉丝列表、文章的评论列表之类的东西。

set:无序集合,会自动去重的那种。可以基于 Set 玩儿交集、并集、差集的操作,比如交集吧,我们可以把两个人的好友列表整一个交集,看看俩人的共同好友是谁。

sortset:排序的 Set,去重但可以排序,写进去的时候给一个分数,自动根据分数排序。常用在排行榜

hyperloglog、geo、pub\sub、位图、布隆过滤器

如果有大量的key需要设置同一时间过期,一般需要注意什么

如果有大量的key过期的时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象,严重的会出现缓存雪崩。解决方法:在时间上加一个随机时间,让过期的时间分散一些。

redis分布式锁

为了提高服务的并发能力,一般都是多容器多进程水平化扩展部署,这样会存在进程安全问题,这个时候可以使用redis分布式锁来保证进程安全。一般使用的时候会设置一个过期时间,防止拿到锁的进程在释放前进程异常锁未释放,另外由于过期时间可能预估不准,导致提前释放,别的进程拿到锁的时候,该进程给释放了的问题,一般setnx的时候会将value设置一个和进程有关的唯一id,释放的时候先看看是不是自己的value,然后再去释放。

然而上面还是会有问题,例如使用的高可用的redis集群,在主节点上获得锁,然后数据还没有同步到从节点主节点挂了,那么就这个时候从节点变成主节点后是没有锁的。解决方法:使用redlock,就是大多数redis节点加锁成功才是成功。

以上都是属于悲观锁。

在众多的key里面拿到自己合适的key的集合

keys,会导致一定的线程阻塞,scan,不会阻塞,但是会拿到重复的,返回一个游标,根据游标再次取拿取。

redis做异步队列

list结构做队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来,如果长时间阻塞会有一个空闲断开。

pub\sub

可以实现一个1:N的消息队列,如果消费者下线,消息会丢失,最好使用专业的消息队列rocketmq。

redis5.0版本有一个stream机制,用法和kafka差不多了。

Redis如何实现延时队列?

使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。

redis数据持久化

RDB做镜像全量持久化,AOF做增量持久化。

RDB是fork一个子进程,然后子进程将数据快照以一种二进制的方式持久化数据。AOF是会将每个数据改动命令增量的保存,时间久了对应的文件很大,这里会有一个文件重写的过程。

pipline机制,有什么好处?

可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。

redis的同步机制

Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将RDB文件全量同步到复制节点,复制节点接受完成后将RDB镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。后续的增量数据通过AOF日志同步即可,有点类似数据库的binlog。

redis集群

Redis Sentinal 着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。

Redis Cluster 着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。

缓存雪崩和解决方法

redis做缓存的时候,如果设置key有失效时间,如果大量的key都在统一时间失效,而这个时候服务器的请求量已经很大,那么请求会直接都打到数据库上,数据库扛不住会挂了,这个时候即使把数据库服务重启也会被新的请求打挂。

解决方法:对于有失效的key,在失效时间随机加一个数值,防止同一时间大面积失效,另外服务要做熔断。

缓存穿透和解决方案

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,我们数据库的 id 都是1开始自增上去的,如发起为id值为 -1 的数据或 id 为特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大,严重会击垮数据库。

解决方案:对于不合理的请求参数做好校验,Redis还有一个高级用法**布隆过滤器(Bloom Filter)**这个也能很好的防止缓存穿透的发生,他的原理也很简单就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你return就好了,存在你就去查了DB刷新KV再return。

缓存击穿和解决方案

至于缓存击穿嘛,这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓存失效,打崩了DB,而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

解决方案:设置热点数据永远不过期。或者加上互斥锁就能搞定了

关于缓存的三个问题的一些技巧

一般避免以上情况发生我们从三个时间段去分析下:

  • 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。
  • 事中:本地 ehcache 缓存 + Hystrix 限流+降级,避免** MySQL** 被打死。
  • 事后:Redis 持久化 RDB+AOF,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。

redis为什么会很快

Redis采用的是基于内存的采用的是单进程单线程模型的 KV 数据库,由C语言编写,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)

  • 完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。它的,数据存在内存中,类似于HashMapHashMap的优势就是查找和操作的时间复杂度都是O(1);
  • 数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
  • 采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
  • 使用多路I/O复用模型,非阻塞IO;
  • 使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

redis是单线程的,服务器一般都是多核的,这个是不是一个浪费?

我们可以单机多开redis实例,另外为了解决单机的瓶颈,我们可以使用集群化部署,Redis cluster,并且是主从同步读写分离,类似Mysql的主从同步,Redis cluster 支撑 N 个 Redis master node,每个master node都可以挂载多个 slave node

这样整个 Redis 就可以横向扩容了。如果你要支撑更大数据量的缓存,那就横向扩容更多的 master 节点,每个 master 节点就能存放更多的数据了。

redis集群化部署的时候,数据怎么交互,数据怎么持久化

  • RDB:RDB 持久化机制,是对 Redis 中的数据执行周期性的持久化。
  • AOF:AOF 机制对每条写入命令作为日志,以 append-only 的模式写入一个日志文件中,因为这个模式是只追加的方式,所以没有任何磁盘寻址的开销,所以很快,有点像Mysql中的binlog

两种方式都可以把Redis内存中的数据持久化到磁盘上,然后再将这些数据备份到别的地方去,RDB更适合做冷备AOF更适合做热备

两种数据持久化的优缺点

RDB

优点:

他会生成多个数据文件,每个数据文件分别都代表了某一时刻Redis里面的数据,这种方式,有没有觉得很适合做冷备,完整的数据运维设置定时任务,定时同步到远端的服务器,比如阿里的云服务,这样一旦线上挂了,你想恢复多少分钟之前的数据,就去远端拷贝一份之前的数据就好了。

RDBRedis的性能影响非常小,是因为在同步数据的时候他只是fork了一个子进程去做持久化的,而且他在数据恢复的时候速度比AOF来的快。

缺点:

RDB都是快照文件,都是默认五分钟甚至更久的时间才会生成一次,这意味着你这次同步到下次同步这中间五分钟的数据都很可能全部丢失掉。AOF则最多丢一秒的数据,数据完整性上高下立判。

还有就是RDB在生成数据快照的时候,如果文件很大,客户端可能会暂停几毫秒甚至几秒,你公司在做秒杀的时候他刚好在这个时候fork了一个子进程去生成一个大快照,哦豁,出大问题。

我们再来说说AOF

优点:

上面提到了,RDB五分钟一次生成快照,但是AOF是一秒一次去通过一个后台的线程fsync操作,那最多丢这一秒的数据。

AOF在对日志文件进行操作的时候是以append-only的方式去写的,他只是追加的方式写数据,自然就少了很多磁盘寻址的开销了,写入性能惊人,文件也不容易破损。

AOF的日志是通过一个叫非常可读的方式记录的,这样的特性就适合做灾难性数据误删除的紧急恢复了,比如公司的实习生通过flushall清空了所有的数据,只要这个时候后台重写还没发生,你马上拷贝一份AOF日志文件,把最后一条flushall命令删了就完事了。

缺点:

一样的数据,AOF文件比RDB还要大。

AOF开启后,Redis支持写的QPS会比RDB支持写的要低,他不是每秒都要去异步刷新一次日志嘛fsync,当然即使这样性能还是很高,我记得ElasticSearch也是这样的,异步刷新缓存区的数据去持久化,为啥这么做呢,不直接来一条怼一条呢,那我会告诉你这样性能可能低到没办法用的,大家可以思考下为啥哟。

两种数据持久化方式怎么选择

都用,你单独用RDB你会丢失很多数据,你单独用AOF,你数据恢复没RDB来的快,真出什么时候第一时间用RDB恢复,然后AOF做数据补全,真香!冷备热备一起上,才是互联网时代一个高健壮性系统的王道。

redis有没有其他的集群保证高可用

哨兵集群sentinel,哨兵必须用三个实例去保证自己的健壮性的,哨兵+主从并不能保证数据不丢失,但是可以保证集群的高可用

哨兵组件的主要功能:

  • 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。
  • 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
  • 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
  • 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

主从同步直接的数据怎么做的同步

之所以用主从架构,是因为单机QPS有上限,如果一台机器又读又写,在高并发的时候,很难扛得住,如果这个时候用master写,数据同步给slave,然后读的时候走slave机器,可以分发掉很多的请求,可以扩容的时候可以实现很好的水平扩容。

你启动一台slave 的时候,他会发送一个psync命令给master ,如果是这个slave第一次连接到master,他会触发一个全量复制。master就会启动一个线程,生成RDB快照,还会把新的写请求都缓存在内存中,RDB文件生成后,master会将这个RDB发送给slave的,slave拿到之后做的第一件事情就是写进本地的磁盘,然后加载进内存,然后master会把内存里面缓存的那些新命名都发给slave。

redis的过期策略

定期删除+惰性删除两种。

默认100ms就随机抽一些设置了过期时间的key,去检查是否过期,过期了就删了。

惰性删除,我不主动删,我懒,我等你来查询了我看看你过期没,过期就删了还不给你返回,没过期该怎么样就怎么样。

如果,定期没删,我也没查询,那可咋整?

内存淘汰机制

官网上给到的内存淘汰机制是以下几个:

  • noeviction:返回错误当内存限制达到并且客户端尝试执行会让更多内存被使用的命令(大部分的写入指令,但DEL和几个例外)

  • allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。

  • volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。

  • allkeys-random: 回收随机的键使得新添加的数据有空间存放。

  • volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。

  • volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。

    如果没有键满足回收的前提条件的话,策略volatile-lru, volatile-random以及volatile-ttl就和noeviction 差不多了。

redis的线程模型

Redis 内部使用文件事件处理器 file event handler,这个文件事件处理器是单线程的,所以 Redis 才叫做单线程的模型。它采用 IO 多路复用机制同时监听多个 Socket,根据 Socket 上的事件来选择对应的事件处理器进行处理。

文件事件处理器的结构包含 4 个部分:

  • 多个 Socket
  • IO 多路复用程序
  • 文件事件分派器
  • 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)

多个 Socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 Socket,会将 Socket 产生的事件放入队列中排队,事件分派器每次从队列中取出一个事件,把该事件交给对应的事件处理器进行处理。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值