Redis学习笔记

Redis学习笔记

1、什么是Redis

Redis是开源的,性能极高的nosql数据库,key-value数据库,并且提供有多种语言的的API的非关系型数据库

  • Redis读写速度快,读110000次/s,写81000次/s
  • Redis支持数据持久化,可以将内存中的数据持久化到磁盘中,重启时候可以直接读取使用
  • Redis支持备份,即master-slave模式的数据备份
  • 丰富的数据类型:string、hash、set、list、zset
  • Redis的所有操作都是原子性的,要你成功,要么失败不执行
  • 还有丰富的特性:Redis支持publish/subscribe,通知,key过期

优势

  • 性能极高,读写速度快
  • 原子性-所有的操作都是原子性的
  • 多个操作也支持事务,即原子性,通过MULTLI和EXEC指令包起来
  • 丰富的特性

Redis与其它key-value存储有什么不同

Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其它数据库的进化路径。

Redis运行在内存中,但是可以持久化到磁盘,所以在对不同数据集进行高速读写时候,需要权衡内存,因为数据量不能大雨硬盘内存。在内存数据库方面的另一个优点就是,相比在磁盘上香甜的复杂数据结构,在内存中操作起来更加简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

Redis是单进程单线程的?

Redis是单进程单线程的,redis利用队列技术将并发变为串行访问,消除了传统数据库串行控制的开销。

Redis的持久化机制是什么?各自的优缺点?

Reids提供有两种持久化机制RDB(默认)和AOF机制

RBD:是Redis DataBase缩写快照

RDB是redis默认持久化方式。按照一定的时间将内存的数据以快照的形式保存到硬盘中,对应产生的数据文件未dump.rbd。通过配置文件中的save参数来定义快照周期。

img

优点:

  1. 只有一个文件dump.rdb,方便持久化
  2. 容灾性好,一个文件可以保存到安全的磁盘。
  3. 性能最大化,fork子进程来完成写操作,让主进程继续处理命令,所以IO最大化。使用单独子进程来进行持久化,主进程不会有任何IO操作,保证了redis的高性能
  4. 相对于数据集大时候,比AOF的启动效率更高

缺点:

  1. 数据安全性低。RDB是间隔一段时间进行持久化,如果持久化之间redis发生故障,会发生数据丢失。所以这种方式更适合数据要求不严谨的时候
  2. AOF(Append-only file)持久化方式:是指所有的命令行记录以redis命令请求协议的格式完成持久化存储保存为aof文件。

AOF:持久化

AOF持久化(即Append-Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中,当重启redis会重新将持久化的日志文件回复数据。

当两种方式同时开启时候,数据恢复Redis会优先选择AOF恢复。

img

优点:

  1. 数据安全,aof持久化可以配置appendfsunc属性,有always,每进行一次命令操作就记录到aof文件中一次。
  2. 通过append模式写文件,即使中途服务器宕机,可以通过redis-check-aof工具解决数据一致性问题
  3. AOF机制的rewrite模式。AOF文件没被rewrite之前(文件过大时会对命令进行合并重写),可以删除其中某些命令(比如误操作的flushall)

缺点:

  1. AOF文件比RDB文件大,且恢复速度慢
  2. 数据集大的时候,比rdb启动效率低

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

  1. master最好不要做任何持久化工作,如rdb内存快照和aof日志文件

  2. 如果数据比较重要,某个slave开启AOF备份数据,策略设置为每秒同步一次

  3. 为了主从复杂的速度和连接的稳定性,master和slave最好在同一个局域网内

  4. 避免在压力很大的主库上增加从库

  5. 主从复制不要用图状结构,用单向链表结构更为稳定,即:master->Slave1->Slave2->Slave3

    这样的结构方面解决单电故障问题,实现Slave对master的替换。如果master挂了,可以离家启用Slave做master,其它的不变。

使用过Redis的分布式锁吗,它时怎么实现的?

先拿setnx来争抢锁,抢到之后,在用expire给锁加一个过期时间防止忘记了释放。

什么是缓存雪崩?

缓存雪崩我们可以简单理解为:由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期),所有原本应该访问缓存的请求都去查询数据库了,而对数据库cpu和内存造成了巨大压力,严重的会造成数据库宕机。从而形成一系列连锁反应,造成整个系统崩溃。

当缓存服务器重启或者大量缓存集中在某一个时间段实效,这样在实效的时候,会给后端带来很大压力。导致系统崩溃。

解决方案:

大多数系统设计者考虑用加锁(最多的解决方案)或者队列方式保证不会有大量的线程对数据库一次性进行读写,从而避免实效时大量的并发请求落到低层存储系统上。还有一个简单的方案就是将缓存失效时间分散开。

如何避免?

  1. 在缓存失效后,通过加锁或者队列来控制数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待
  2. 做二级缓存,A1为原始缓存,A2位拷贝缓存,A1失效时候,可以访问A2,A1缓存时间设置短期,A2设置长期
  3. 不同的key,设置不同的过期时间,让缓存失效时间点尽量均匀

什么是缓存穿透?

缓存穿透是指用户查询数据,在数据库没有,自然缓存中也不会有。每次都要去数据库再查询一遍,然后返回空,这样请求就绕过缓存直接查询数据库,如果恶意请求量很大,就会对后端系统造成很大压力。这就叫做缓存穿透。

解决方法:

  1. 最常见的则是采用隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被这个bitmap拦截掉,从而避免对底层存储系统的查询压力。
  2. 也有一个更为简单粗暴的方法,如果一个查询返回的数据为空(不管实数据不存在还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间很短,最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种方法最简单粗暴。

Redis缓存击穿(热点key)

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

解决方案:对缓存查询加锁,如果key不存在,就加锁,然后查DB入缓存,然后解锁;其它进行如果发现有锁就等待,然后等待解锁后返回数据或进入DB查询。

什么是缓存预热?

缓存预热是比较常见的概念,相信很多小伙伴都可以很容易理解,缓存预热就是系统上线后,将相关的缓存数据直接加载到缓存系统。这样就可以避免在用户请求的时候,线查询数据库,然后再将数据缓存的问题。用户直接查询事先被预热的缓存数据。

解决思路:

  1. 直接写个缓存刷新页面,上线时候手动操作下;
  2. 数据量不大,可以在项目启动的时候自动进行加载;
  3. 定时刷新缓存;

什么是缓存降级?

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

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

以参考日志级别设置预案:

  1. 一般:比如有些服务偶尔因为网络抖动或者服务正在上线而超时,可以自动降级;
  2. 警告:有些服务在一段时间内成功率有波动(如在95~100%之间),可以自动降级或人工降级,并发送警告。
  3. 错误:比如可用率低于90%,或者数据库连接池被打爆了,或者访问量突然猛增到系统能承受的最大阀值,此时可以根据情况自动降级或者人工降级
  4. 严重错误:比如因为特殊原因数据错误了,此时需要紧急人工降级

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

缓存热点数据和缓存冷数据

热点数据缓存才有意义有价值

对于冷数据而言,大部分数据可能害没有再次访问到就已经被挤出内存,不仅占用内存,而且价值不大。频繁修改的数据,看情况考虑使用缓存,对于上面两个例子,寿星列表、导航信息都存在一个特点,就是信息修改频率不高,读取通常非常高的场景。

对于热点数据,比如我们的某IM产品,生日祝福模块,当天的寿星列表,缓存以后可能读取数十万次。再举个例子,某导航产品,我们将导航信息,缓存以后可能读取数百万次。

数据更新前至少读取两次,缓存才有意义。这个是最基本的策略,如果缓存还没有起作用就失效,那就没有太大的价值了。

Redis为什么是单线程的?

Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存大小或者网络带宽。几人单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章的采用单线程方案了。

Redis利用队列技术将兵法访问变为串行访问

  1. 绝大部份请求都是存粹的内存操作(非常的快)

  2. 采用了单线程,避免了不必要的上下文切换和竞争条件

  3. 非阻塞IO优点:

    1. 速度快,因为数据存在内存中,类似于HashMap,hashMap的优势就是插座和操作的时间复杂度都是O(1)
    2. 支持丰富的数据类型,支持string、list、set、sorted set 、hash
    3. 支持事务,操作都是原子性,所谓的原子性就是对数据的更改,要么全部执行,要么全部不执行
    4. 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除

    同时有多个子系统去set一个key,这个时候要注意什么嗯?不推荐使用redis的事务机制。因为我们的生存环境,基本都是redis集群环境,做了数据分片操作。你一个事务中涉及到多个key操作的时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。

    • 如果对这个key操作,不要求顺序:准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可
    • 如果对这个key操作,要求顺序:分布式锁加时间戳。假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推
    • 利用队列,将set方法变成串行访问也可以在redis遇到高并发时候保证读写key的一致性。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值