(R计划分享)浅谈非关系型数据库Redis

一、Redis是什么

百度百科:Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

Redis是一种Key-Value存储形式的非关系型内存数据库,整个数据库加载在内存当中操作,定期通过异步操作把数据库中的数据flush到硬盘上进行保存。

整个数据库加载在内存当中操作,定期通过异步操作把数据库中的数据flush到硬盘上进行保存。

优点

  • 读写性能极高, Redis能读的速度是110000次/s,写的速度是81000次/s。
  • 支持数据持久化,支持AOF和RDB两种持久化方式。
  • 支持事务, Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
  • 数据结构丰富,除了支持string类型的value外,还支持hash、set、zset、list等数据结构。
  • 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等特性。

缺点

  • 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。

二、Redis安装

Linux:Linux安装包下载

Windows:redis下载安装教程-Windows版本(详细)

注意:Redis官方只有Linux系统安装包,Windows版本是他人封装出来的。

 

三、基本数据类型

  • string:字符串类型(键-值)
  • list:列表类型(键-集合 可以重复)
  • set:集合类型(键-集合 不可以重复)
  • hash:哈希类型(键-键值对)
  • zset:有序集合(键-值-值 不可以重复)

3.1 string

set [key] [value]      插入键值对
get [key]              获取值
incr [key]             自增(值为integer类型)
decr [key]             自减(值为integer类型)
mget [key...]          获取多个值
del [key]              删除键值对

3.2 list

lpush [key] [value...]      从列表list的左边插入一个元素
lpop [key]                  从列表list的左边移除一个元素
rpush [key] [value...]      从列表list的右边插入一个元素
rpop [key]                  从列表list的右边移除一个元素
lrange [key] [start] [stop] 从列表中获取对应下标的值[start,stop]
llen [key]                  打印当前列表list中的元素个数
lindex [key] [index]        获取指定列表中指定下标的元素
lrem [key] [count] [value]  根据count值移除指定列表中跟value相等的数据
//count>0:从列表的左侧移除count个跟value相等的数据;
//count<0:从列表的右侧移除count个跟vlaue相等的数据;
//count=0:从列表中移除所有跟value相等的数据
ltrim key startIndex endIndex 截取指定列表中指定下标区间的元素组成新的列表,并且赋值给key
lset key index value 将指定列表中指定下标的元素设置为指定值
linsert key before/after pivot vlaue 将value插入到指定列表中位于pivot元素之前/之后的位置

 

3.3 set

sadd [key] [member...]     往set中添加数据()
srem [key] [member...] 从set中删除数据
smembers [key] 获取集合 key 中的所有成员元素,不存在的 key 视为空集合
scard [key] 查看set中存在的元素个数
sismember [key] [member] 查看set中是否存在某个数据

3.4 hash

hset [key] [field] [value]   往hash里,添加key-[field-value]
hget [key] [field] 通过key值,从hash里取对应的value
hmget [key] [field...] 一次性获取多个key的value
hmset [key] [field value...] 一次性添加多个key的value
hgetall <key> 查看key的所有键值对
hkeys <key> 返回所有hash表中的key的所有域
hexists <key> <field> 查看hash表中,给定key的域field是否存在。如果存在,则返回1

3.5 zset

zadd [key] [score member ...]  添加数据,score表示member成员的得分,根据得分排序
zcard [key]                    查询成员数据个数
zrange [key] [start] [stop]    数据排序,根据分数从小到大
zrevrange [key] [start] [stop] 数据排序,根据分数从大到小

 

3.6 特殊数据类型

1、Bitmap:

位图,Bitmap想象成一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在Bitmap中叫做偏移量。使用Bitmap实现统计功能,更省空间。如果只需要统计数据的二值状态,例如商品有没有、用户在不在等,就可以使用 Bitmap,因为它只用一个 bit 位就能表示 0 或 1。

2、HyperLogLog:

HyperLogLog 是一种用于统计基数的数据集合类型,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。

场景:统计网页的UV(即Unique Visitor,不重复访客,一个人访问某个网站多次,但是还是只计算为一次)。

要注意,HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。

3、Geospatial :

主要用于存储地理位置信息,并对存储的信息进行操作,适用场景如朋友的定位、附近的人、打车距离计算等。

 四、Redis的高性能

  • 内存存储:Redis是使用内存(in-memeroy)存储,没有磁盘IO上的开销。数据存在内存中,类似于 HashMap,HashMap 的优势就是查找和操作的时间复杂度都是O(1)。

  • 单线程实现( Redis 6.0以前):Redis使用单个线程处理请求,避免了多个线程之间线程切换和锁资源争用的开销。注意:单线程是指的是在核心网络模型中,网络请求模块使用一个线程来处理,即一个线程处理所有网络请求。

  • 非阻塞IO:Redis使用多路复用IO技术,将epoll作为I/O多路复用技术的实现,再加上Redis自身的事件处理模型将epoll中的连接、读写、关闭都转换为事件,不在网络I/O上浪费过多的时间。

  • 优化的数据结构:Redis有诸多可以直接应用的优化数据结构的实现,应用层可以直接使用原生的数据结构提升性能。

  • 使用底层模型不同:Redis直接自己构建了 VM (虚拟内存)机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。

Redis属于缓存数据库,数据存放在内存中,当程序获取数据时,直接通过内存调用,极大的提高了Redis 的性能。

  

 在一般项目中,常常是根据不同的应用场景,结合各数据库的特点,选择性的使用数据库,例如MySQL和Redis这两种数据库结合起来使用会达到一种比较理想的效果。

 

五、Redis的内存回收策略

5.1 过期回收策略

删除到达过期时间的键对象。

Redis所有的键都可以设置过期属性,内部保存在过期字典中。由于进程内保存了大量的键,维护每个键精准的过期删除机制会导致消耗大量的CPU,对于单线程的Redis来说成本过高,因此Redis采用惰性删除和定时任务删除机制实现过期键的内存回收。
  • 惰性删除:惰性删除用于当客户端读取带有超时属性的键时,如果已经超过键设置的过期时间,会执行删除操作并返回空,这种策略是出于节省CPU成本考虑,不需要单独维护TTL链表来处理过期键的删除。但是单独用这种方式存在内存泄露的问题,当过期键一直没有访问将无法得到及时删除,从而导致内存不能及时释放。正因为如此,Redis还提供另一种定时任务删除机制作为惰性删除的补充。
  • 定时任务删除:Redis内部维护一个定时任务,默认每秒运行10次(通过配置hz控制)。定时任务中删除过期键逻辑采用了自适应算法,根据键的过期比例,使用快慢两种速率模式回收键。
  比如:
  1. 定时任务在每个数据库空间随机检查20个键,当发现过期时删除对应的键。
  2. 如果超过检查数25%的键过期,循环执行回收逻辑直到不足25%或运行超时为止,慢模式下超时时间为25ms。
  3. 如果之前回收键逻辑超时,则在Redis触发内部事件之前再次以快模式运行回收过期键任务,快模式下超时时间为1ms且2s内只能运行1次。
  4. 快慢两种模式内部删除逻辑相同,只是执行的超时时间不同。

5.2 内存溢出控制策略

当Redis所用内存达到maxmemory上限时会触发相应的溢出控制策略。
  具体策略受maxmemory-policy参数控制,Redis支持6种策略,如下所示:
  1. noeviction:默认策略,当内存不足以容纳新写入数据时,新写入操作会报错。应该没人用吧。
  2. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。推荐使用,目前很多项目在用这种。
  3. allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。很少用。
  4. volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。不推荐。
  5. volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。依然不推荐。
  6. volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。不推荐。如果没有对应的键,则回退到noeviction策略。

六、Redis缓存雪崩、缓存穿透、缓存击穿

6.1缓存雪崩

redis雪崩是指,在某个时间key大量失效,或者redis服务宕机了,突然造成数据库访问压力急剧增大,像雪崩一样。redis雪崩危害巨大,甚至有可能导致整个服务器宕机,给公司造成巨大的经济损失。

解决方法:

1、建立Redis集群,避免宕机。

2、设置超时时间的时候要设置随机值,不要设置固定值

ttl [key]              查看key的超时时间,以秒计算,-1代表没有超时时间,如果不存在key或者key已经超时则为-2
expire [key] [seconds] 设置超时时间戳,以秒为单位

 

6.2缓存穿透

缓存穿透是指缓存和数据库中都没有这个数据,而用户不断发起请求。由于缓存是不命中时被动写的,并且出于容错考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,失去了缓存的意义。

解决办法:

1、设置过滤器,对于不存在的key进行过滤。

例如:

布隆过滤器,将所有可能存在的数据哈希到一个足够大的bitmap中,一个一定不存在的数据会被 这个bitmap拦截掉,从而避免了对底层存储系统的查询压力。

2、不存在的key也加到缓存中,设置值为null,但它的过期时间会很短,最长不超过五分钟。(常用)

6.3缓存击穿

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),某个时刻由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案:
1.设置热点数据永不过期
2.加互斥锁(mutex key)

业界比较常用的做法,是使用mutex。简单地来说,就是在缓存失效的时候(判断拿出来的值为空),不是立即去load db,而是先使用缓存工具的某些带成功操作返回值的操作(比如Redis的SETNX或者Memcache的ADD)去set一个mutex key,当操作返回成功时,再进行load db的操作并回设缓存;否则,就重试整个get缓存的方法。
 
  • 缓存雪崩    Redis服务宕机或大量key失效
  • 缓存穿透    Redis和数据库都没有这个数据
  • 缓存击穿    Redis中没有数据,数据库中有数据

七、Redis持久化

数据存放在内存中,虽然访问速度极快,但是数据存储却不安全,若出现断电等情况,内存中数据将会丢失,所以Redis有一系列持久化机制。

7.1RDB(快照)

RDB持久化是指在指定的时间间隔内将内存中的数据集快照写入磁盘。也是默认的持久化方式,这种方式是就是将内存中数据以快照的方式写入到二进制文件中,默认的文件名为dump.rdb。

修改redis.config中配置文件

 

 触发条件,900秒内,1个key值被修改。(两者必须同时满足才能够)

7.2AOF(全量)

AOF持久化后,每执行一条会更改Redis中的数据的命令,Redis就会将该命令写入硬盘中的AOF文件,这一过程显然会降低Redis的性能。

需要手动设置appendonly为yes

 

posted @ 2022-07-05 15:51  砰砰的猿  阅读(131)  评论(0编辑  收藏  举报