简约而不简单的NoSql数据库 - Redis

2020-06-23 00:00:00 数据 文件 缓存 队列 持久

每日一遍,防止脱发:

程序猿的读书历程:x语言入门—>x语言应用实践—>x语言高阶编程—>x语言的科学与艺术—>编程之美—>编程之道—>编程之禅—>颈椎病康复指南。


Redis简介:

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API传统的数据库综训ACID规则,NoSql(Not Only Sql)是对不同于传统的关系型数据库的数据库管理系统的统称,一般为分布式,即遵循CAP定理。


1. 数据类型

Redis非关系型数据库共支持String、Hash、List、Set、Short Set(zSet) 五种数据类型

  • String(字符串):String字符串类型是二进制安全的,Redis的Strig类型可以保存任何数据,如图片 文件或者序列化的对象。

格式:存入 -- set key value 读出 -- get key

  • Hash(哈希):Redis 的 Hash 是一个键值对的集合,内部是一个 String 类型的 field 和 value 的映射表,所以Hash特别适合储存对象。

格式:存入 -- hmset key field1 value1 field2 value2 读出 -- hget key field

  • List(列表):Redis的List类型是双端循环列表,分别可以从左右两边插入及取出数据,既可以作为队列使用,也可以一作为栈使用。

格式:存入 -- LPUSH key value 【values.........】--从队列的左边入队一个或多个元素

-- RPUSH key value【values.........】--从队列的右边入队一个或多个元素

读出 -- LPOP key -- 从队列的左端出队一个元素

-- RPOP key -- 从队列的右端出队一个元素

  • Set(无序集合):Redis 的 Set 是 String 类型的无序集合,集合底层是通过哈希表实现的

格式:存入 -- SADD key value 读出 -- SGET key

  • Short Set(有序集合):Redis 的 zSet 集合是一个 String 类型的有序集合,该集合中的元素有序且不重复,集合中的每个元素都关联一个double类型的分数,Redis 通过这些分数来为集合中的个元素进行从小到大的排序。

格式:存入 -- ZADD key score value 读出 -- ZGET key


2. Redis 的数据持久化方式

所谓数据持久化,其实就是把内存中的数据写到磁盘上,防止因为服务器宕机导致数据丢失。Redis 提供的数据持久化方式有两种 ,即 RDB(默认方式)和 AOF。

  • RDB:在RDB方式下,有两种持久化策略,一种是通过手动执行Redis的持久化数据命令来让Redis进行一次数据快照,另一种则是根据你所配置的配置文件的策略达到这些策略的某些条件时来自动持久化数据。如果我们选择手动执行持久化命令,依然存在两种选择,包括save 命令和 bgSave 命令。

a】save:save 命令执行的操作在Redis的主线程中执行,因此会阻塞当前主线程执行其他操作,应该尽 量避免使用。

b】bgSave:bgSave则是调用Fork产生子进程,父进程继续处理请求。子进程将数据写入临时文件,并在写入完成后替换掉原来的.rdb文件。Fork在执行时,父进程与子进程内存共享,所以为了不影响子进程做数据快照,在这期间修改的数据,将会被复制一份,并且是不进入共享内存的。所以说

  • AOF:在AOF模式下,你所执行的任何一条指令都会被写入AOF的持久化文件中,但是并不会立即将命令写入磁盘文件中,而是写入硬盘缓存中,需要通过自己配置的策略来实现将指令多久从磁盘缓存写入到磁盘文件中。

a】everysec:每秒执行一次持久化

b】always:每次操作都会立即写入aof文件中

c】no:不主动执行持久化操作,默认30s一次,可以通过客户端主动执行持久化命令

两种持久化方式的优势和劣势

  • RDB每次进行快照方式都会重新记录整个数据集的全部信息,RDB在恢复数据时更快,可以大化Redis性能,子进程对父进程无任何性能影响。
  • AOF有序的记录了Redis的全部命令操作,意外情况下数据丢失甚少,它不断的对aof文件添加日志操作记录,但是这个文件只会保留能够还原Redis数据库的少操作,内部会对重复的命令进行优化,也就是对.aof文件的重写,并且在还原时系统会优先加载.aof文件来还原系统。
  • .aof文件比.rdb文件更新频率高,更安全也更大,但是rdb性能比aof好。

3. Redis的架构模式

  • 单机版

优势:简单

劣势:内存容量有限,处理能力有限,无法高可用

  • 主从复制,读写分离

优势:保证高可用,监控各个节点,自动故障迁移

劣势:主从模式,切换需要时间,可能会丢失数据

  • 集群(proxy型)

优势:可以合理的分散各个节点的压力,支持失败节点自动删除,多种hash算法

劣势:其自身不支持故障转移,而且可拓展性差


4. 关于Redis可能会问到的面试题

  1. 使用过Redis分布式锁么,它是怎么实现的?

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!


2. 使用过Redis做异步队列么,你是怎么用的?有什么缺点?


一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
缺点:
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
能不能生产一次消费多次呢?
使用pub/sub主题订阅者模式,可以实现1:N的消息队列。

3. 什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透


一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?
1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。
如何避免?
1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期
3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

相关文章