赞
踩
redis-benchmark 性能测试工具
redis-check-aof 日志文件检测工(比如断电造成日志损坏,可以检测并修复)
redis-check-dump 快照文件检测工具,效果类上
redis-cli 客户端
redis-server 服务端
redis.windows.conf redis配置文件,在启动redis服务器的时候,必须要制定配置文件,那么相当于于一个配置文件就是一个redis数据库服务器。
Redis 在 4.0 之前一直采用单线程的模式,原因如下:
Redis 4.0 中的多线程:惰性删除(异步删除)
我们使用 del 指令可以很快的删除数据,但是当被删除的 key 是一个非常大的对象数据时,那么 del 指令就会造成 Redis 主线程卡顿,因此使用惰性删除可以有效的避免 Redis 卡顿的问题。Redis 在 4.0 中引入了惰性删除(异步删除),意思是说我们可以使用异步的方式对 Redis 中的数据进行删除操作了,例如 unlink key
/ flushdb async
/ flushall async
等命令,他们的执行示例如下:
> unlink key # 后台删除某个 key
> OK # 执行成功
> flushall async # 清空所有数据
> OK # 执行成功
这样处理的好处是不会导致 Redis 主线程卡顿,会把这些删除操作交给后台线程来执行。
redis6.0多线程
Redis 6.0 中新增了多线程的功能来提高 I/O 的读写性能
Redis 4.0 版本中虽然引入了多线程,但此版本中的多线程只能用于大数据量的异步删除,然而对于非删除操作的意义并不是
Redis 6.0 默认是禁用多线程的,可以通过修改 Redis 的配置文件 开启 。官方的建议是如果为 4 核的 CPU,建议线程数设置为 2 或 3,如果为 8 核 CPU 建议线程数设置为 6,线程数一定要小于机器核数,线程数并不是越大越好。
常见的数据类型
类型 | 特点 | 使用场景 |
---|---|---|
string字符串 | key=value的形式,可存数字 | 定时持久化,常规计数 |
hash映射表 | string类型的key=value的映射表,适合存储对象 | 存储部分变更数据,比如用户信息表 |
list链表 | 有序可重复的链表 | 消息队列 |
set集合 | 无序不可重复的序列 | 常用交并差集,比如可以求共同关注的博主 |
zset有序集合 | 带score排名的无序不可重复序列 | 排行榜 |
zset有序集合是由 ziplist (压缩列表) 或 skiplist (跳跃表) 组成的。
当数据比较少时,有序集合使用的是 ziplist 存储的,如下代码所示:
127.0.0.1:6379> zadd myzset 1 db 2 redis 3 mysql
(integer) 3
127.0.0.1:6379> object encoding myzset
"ziplist"
从结果可以看出,有序集合把 myset 键值对存储在 ziplist 结构中了。 有序集合使用 ziplist 格式存储必须满足以下两个条件:
当有序集合保存的所有元素成员的长度大于 64 字节时,有序集合就会从 ziplist 转换成为 skiplist。
高级数据类型
类型 | 使用场景 |
---|---|
GEO(地理位置类型) | Redis 3.2 版本中新增的数据类型,用于存储和查询地理位置的,使用它我们可以实现查询附近的人或查询附近的商家等功能 |
Stream(流类型) | 是 Redis 5.0 版本中新增的数据类型,因为使用 Stream 可以实现消息消费确认的功能,使用“xack key group-key ID”命令,所以此类型的出现给 Redis 更好的实现消息队列提供了很大的帮助。 |
HyperLogLog(统计类型) | Redis 2.8.9 版本添加的数据结构,它用于高性能的基数 (去重) 统计功能,它的缺点就是存在极低的误差率。 |
问题: 假设我们的系统只能为 10 万人同时提供购物服务,但是某一天因为老罗带货突然就涌进了 100 万用户,那么导致的直接后果就是服务器瘫痪,谁也甭想买东西了,所以这个时候我们需要“限流”的功能保证先让一部分用户享受购物的服务,而其他用户进行排队等待购物,这样就可以让整个系统正常的运转了。
滑动时间算法缺点是占用内存空间大,并且是非原子操作;令牌算法为程序级别的单机限流实现方案
Redis 的内存用完指的是 Redis 的运行内存超过了 Redis 设置的最大内存,此值可以通过 Redis 的配置文件 redis.conf 进行设置,设置项为 maxmemory。
127.0.0.1:6379> config get maxmemory
1) "maxmemory"
2) "0"
当此值为 0 时,表示没有内存大小限制,直到耗尽机器中所有的内存为止,这是 Redis 服务器端在 64 位操作系统下的默认值。(32 位操作系统,默认最大内存值为 3GB。)
Redis 内存淘汰策略可以使用 config get maxmemory-policy
命令来查看(4.0 版本之后一共有 8 种)
常见的过期策略,有以下三种:
定时删除
惰性删除
定期删除
原理:每隔一段时间检查一次数据库,随机删除一些过期键。 Redis 默认每秒进行 10 次过期扫描,此配置可通过 Redis 的配置文件 redis.conf 进行配置,配置键为 hz
它的默认值是 hz 10
。 需要注意的是:Redis 每次扫描并不是遍历过期字典中的所有键,而是采用随机抽取判断并删除过期键的形式执行的。
流程:
- 从过期字典中随机取出 20 个键;
- 删除这 20 个键中过期的键;
- 如果过期 key 的比例超过 25% ,重复步骤 1。
同时为了保证过期扫描不会出现循环过度,导致线程卡死现象,算法还增加了扫描时间的上限,默认不会超过 25ms。
优点:通过限制删除操作的时长和频率,来减少删除操作对 Redis 主业务的影响,同时也能删除一部分过期的数据减少了过期键对空间的无效占用。
缺点:内存清理方面没有定时删除效果好,同时没有惰性删除使用的系统资源少。
7.1 Redis 实现分布式锁可以通过以下两种手段来实现:
7.2 分布式死锁
在系统中当一个程序在创建了分布式锁之后,因为某些特殊的原因导致程序意外退出了,那么这个锁将永远不会被释放,就造成了死锁的问题。
7.3 锁被误删
假设锁的最大超时时间是 30s,应用 1 执行了 35s,然而应用 2 在 30s,锁被自动释放之后,用重新获取并设置了锁,然后在 35s 时,应用 1 执行完之后,就会把应用 2 创建的锁给删除掉。
锁被误删的解决方案是在使用 set
命令创建锁时,给 value 值设置一个归属人标识,例如给应用关联一个 UUID,每次在删除之前先要判断 UUID 是不是属于当前的线程,如果属于在删除,这样就避免了锁被误删的问题。 注意:如果是在代码中执行删除,不能使用先判断再删除的方法,伪代码如下:
if(xxx.equals(xxx)){ // 判断是否是自己的锁
del(luck); // 删除锁
}
因为判断代码和删除代码不具备原子性,因此也不能这样使用,这个时候可以使用 Lua 脚本来执行判断和删除的操作,因为多条 Lua 命令可以保证原子性
统计一个值是否在海量数据中可以使用布隆过滤器,布隆过滤器(Bloom Filter)是 1970 年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都比一般的算法要好的多,缺点是有一定的误识别率和删除困难。也就是说布隆过滤器的优点就是计算和查询速度很快,但是缺点也很明显就是存在一定的误差。
在 Redis 中布隆过滤器的用法如下:
使用示例如下:
127.0.0.1:6379> bf.add user xiaoming
(integer) 1
127.0.0.1:6379> bf.add user xiaohong
(integer) 1
127.0.0.1:6379> bf.add user laowang
(integer) 1
127.0.0.1:6379> bf.exists user laowang
(integer) 1
127.0.0.1:6379> bf.exists user lao
(integer) 0
127.0.0.1:6379> bf.madd user huahua feifei
1) (integer) 1
2) (integer) 1
127.0.0.1:6379> bf.mexists user feifei laomiao
1) (integer) 1
2) (integer) 0
可以看出以上结果没有任何误差,我们再来看一下准确率 bf.reserve
的使用:
127.0.0.1:6379> bf.reserve user 0.01 200
(error) ERR item exists #已经存的 key 设置会报错
127.0.0.1:6379> bf.reserve userlist 0.9 10
OK
可以看出此命令必须在元素刚开始执行,否则会报错,它有三个参数:key、errorrate 和 initialsize。 其中:
布隆过滤器常见使用场景有:
Redis 持久化总共有以下三种方式:
RDB(Redis DataBase)是将某一个时刻的内存快照(Snapshot),以二进制的方式写入磁盘的过程。
RDB 优点:
RDB 缺点:
AOF(Append Only File)中文是附加到文件,顾名思义 AOF 可以把 Redis 每个键值对操作都记录到文件(appendonly.aof)中。Redis 默认是关闭 AOF 持久化的。
AOF 优点:
flushall
命令删除了所有键值信息,只要使用 AOF 文件,删除最后的 flushall
命令,重启 Redis 即可恢复之前误删的数据。AOF 缺点:
混合持久化优点:
混合持久化缺点:
缓存雪崩是指在短时间内,有大量缓存同时过期,导致大量的请求直接查询数据库,从而对数据库造成了巨大的压力,严重情况下可能会导致数据库宕机的情况叫做缓存雪崩。
1.解决方案1.加锁排队
加锁排队可以起到缓冲的作用,防止大量的请求同时操作数据库,但它的缺点是增加了系统的响应时间,降低了系统的吞吐量,牺牲了一部分用户体验。
解决方案2.随机化过期时间
为了避免缓存同时过期,可在设置缓存时添加随机时间,这样就可以极大的避免大量的缓存同时失效。 示例代码如下:
解决方案3.设置二级缓存
二级缓存指的是除了 Redis 本身的缓存,再设置一层缓存,当 Redis 失效之后,先去查询二级缓存。 例如可以设置一个本地缓存,在 Redis 缓存失效的时候先去查询本地缓存而非查询数据库。 加入二级缓存之后程序执行流程,如下图所示:
缓存穿透是指查询数据库和缓存都无数据,因为数据库查询无数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会去查询数据库,这种情况就叫做缓存穿透。
解决方案1.使用过滤器
我们可以使用过滤器来减少对数据库的请求,例如使用我们前面章节所学的布隆过滤器,我们这里简单复习一下布隆过滤器,它的原理是将数据库的数据哈希到 bitmap 中,每次查询之前,先使用布隆过滤器过滤掉一定不存在的无效请求,从而避免了无效请求给数据库带来的查询压力。
解决方案2.缓存空结果
另一种方式是我们可以把每次从数据库查询的数据都保存到缓存中,为了提高前台用户的使用体验 (解决长时间内查询不到任何信息的情况),我们可以将空结果的缓存时间设置的短一些,例如 3-5 分钟。
缓存击穿指的是某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求将会给数据库造成巨大的压力,这种情况就叫做缓存击穿。
解决方案1.加锁排队
此处理方式和缓存雪崩加锁排队的方法类似,都是在查询数据库时加锁排队,缓冲操作请求以此来减少服务器的运行压力。
解决方案2.设置永不过期
对于某些热点缓存,我们可以设置永不过期,这样就能保证缓存的稳定性,但需要注意在数据更改之后,要及时更新此热点缓存,不然就会造成查询结果的误差。
首先来说,缓存预热并不是一个问题,而是使用缓存时的一个优化方案,它可以提高前台用户的使用体验。 缓存预热指的是在系统启动的时候,先把查询结果预存到缓存中,以便用户后面查询时可以直接从缓存中读取,以节约用户的等待时间。
缓存预热的实现思路有以下三种:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。