redis
2022-04-10 17:19:48 0 举报
AI智能生成
redis相关知识
作者其他创作
大纲/内容
redis
面试
Redis为啥这么快
测试命令:
redis-benchmark -t set,lpush -n 100000 -q
SET: 111482.72 requests per second
LPUSH: 118906.06 requests per second
本地测试:每秒11万次的set 和get
redis-benchmark -n 100000 -q script load "redis.call('set','foo','bar')"
script load redis.call('set','foo','bar'): 111731.84 requests per second
每秒执行11万的Lua脚本
这么快的原因:
纯内存结构 key -value结构
单线程
没有创建线程、销毁线程带来的消耗
避免了上下文切换导致的 CPU 消耗
避免了线程之间带来的竞争问题,例如加锁释放锁死锁等等
多路复用
延伸一下什么叫多路复用selector、poll、epoll
异步非阻塞IO
redis如何防止key冲突
1、业务隔离
不同的业务使用不同的redis集群
协议使用redis的不同db。
2、良好的Redis Key的设计
格式:业务标识:系统名称:模块名称:关键词简写
比如:保险:用户管理:用户申请:手机号
Redis Key:bx:um:reg:mobile
redis如何保证高可用
主从复制
哨兵模式集群(解决主节点挂掉不可写的问题,没有主节点)
选举出一个 Sentinel 节点来完成自动故障转移
sentinel节点为奇数个(2n+1)
集群模式
3主3从
Hash 槽(slot)
Redis 集群中有 16384 个散列槽,为了计算给定密钥的散列槽,Redis 对 key 采用 CRC16 算法
slot = crc16(key) mod NUMER_SLOTS
数据持久化
aof
rdb
redis分布式锁存在宕机导致锁丢失,怎么解决
Redis分布式锁实现
锁实现
获取锁(unique_value可以是UUID等)
SET resource_name unique_value NX PX 30000
释放锁(lua脚本中,一定要比较value,防止误解锁)
要点
set命令要用set key value px milliseconds nx;
value要具有唯一性;
释放锁时要验证value值,不能误解锁;
问题:锁丢失场景
在Redis的master节点上拿到了锁;
但是这个加锁的key还没有同步到slave节点;
master故障,发生故障转移,slave节点升级为master节点;
导致锁丢失。
解决
Redlock实现
使用N个完全独立、没有主从关系的Redis master节点以保证他们大多数情况下都不会同时宕机,N一般为奇数。一个客户端需要做如下操作来获取锁:
核心原理
获取当前时间(单位是毫秒)。
轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。比如如果锁自动释放时间是10秒钟,那每个节点锁请求的超时时间可能是5-50毫秒的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。
客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁((N/2) +1),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。
如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。
如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,客户端都会到每个master节点上释放锁,即便是那些他认为没有获取成功的锁。
总结
就是利用多个的主节点,在超过半数以上的主节点获取锁成功,才算成功;否则算失败,回滚–删除之前在所有节点上获取的锁。
redis 大key,热key怎么解决
大key
问题
所谓的bigkey就是存储本身的key值空间太大,或者hash,list,set等存储中value值过多。
场景
1、单个简单的key存储的value很大
2、hash, set,zset,list 中存储过多的元素
3、一个集群存储了上亿的key
1、单个简单的key存储的value很大
2、hash, set,zset,list 中存储过多的元素
3、一个集群存储了上亿的key
产生问题
1.读写bigkey会导致超时严重,甚至阻塞服务。
2.大key相关的删除或者自动过期时,会出现qps突降或者突升的情况,极端情况下,会造成主从复制异常,Redis服务阻塞无法响应请求
解决方法
单个简单的key存储的value很大
对象需要每次都整存整取
可以尝试将对象分拆成几个key-value, 使用multiGet获取值,这样分拆的意义在于分拆单次操作的压力,将操作压力平摊到多个redis实例中,降低对单个redis的IO影响;
该对象每次只需要存取部分数据
可以像第一种做法一样,分拆成几个key-value, 也可以将这个存储在一个hash中,每个field代表一个具体的属性,使用hget,hmget来获取部分的value,使用hset,hmset来更新部分属性
对于value中存储过多元素的key,同样可以将这部分元素拆分,以hash为例,正常的流程是:hget(hashKey, field);hset(hashKey, field, value)。 现在可以固定一个桶数量,比如1w,每次存取的时候,先在本地计算field的hash值,对1w取模,确定field落在哪个key上,newHashKey = hashKey + ( hash(field) % 10000); hset (newHashKey, field, value) ; hget(newHashKey, field),set,zset,list做法类似
hash, set,zset,list 中存储过多的元素
可以对存储元素按一定规则进行分类,分散存储到多个redis实例中。
一个集群存储了上亿的key
转Hash结构存储,即原先是直接使用Redis String 的结构存储,现在将多个key存储在一个Hash结构中
不使用redis,使用其他存储,比如mongodb
如何找到大key
jimdb管理端,拓扑Tab页,点击实例可以使用大key扫描功能,该功能底层使用scan扫描所有key,会影响实例性能,选择业务低峰进行
redis 可使用redis-cli的“--bigkeys”选项查找大Key
redis-cli --bigkeys
热key
介绍
热key问题就是突然有几十万的请求去访问redis上的某个特定key,那么这样会造成流量过于集中,达到物理网卡上限,从而导致这台redis服务器直接宕机。
场景
用户消费的数据远大于生产的数据(热卖商品、热点新闻、热点评论、明星直播)
请求分片集中,超过单 Server 的性能极限。
产生问题
• 流量集中,达到物理网卡上限。
• 请求过多,缓存分片服务被打垮。
• DB 击穿,引起业务雪崩。
解决方法
服务端缓存:即将热点数据缓存至服务端的内存中
增加二级缓存
发现热key以后,可以把热key数据加载到系统JVM并设置合适的缓存过期时间,针对热key的请求就会直接分散到各业务服务器上,防止所有请求同时访问同一台redis。
备份热点key
可以把热点key的数据备份到所有redis的集群节点中,可以通过在热点key后面拼接集群节点编号,然后将这些备份key分散到所有集群节点中,客户端访问热点key的时候也在热点key后面随机拼接集群节点编号,将热点key的请求分散到不同集群节点上。
如何找到热key
redis-cli –hotkeys
必须配合maxmemory-policy的属性
config set maxmemory-policy volatile-lfu
config set maxmemory-policy allkeys-lfu
使用
./redis-cli --hotkeys
凭借业务经验,进行预估哪些是热key
在客户端进行收集。比如在redis客户端执行redis命令之前,加入一行代码进行命令数据收集,,然后通过网络将收集的命令发送出去,确定是对客户端代码有入侵。
redis二进制安全怎么实现
概念
在传输数据时,保证二进制数据的信息安全,也就是不被篡改、破译等,如果被攻击,能够及时检测出来
c字符串
C字符串中的字符必须符合某种编码(比如ASCII),并且除了字符串的末尾之外,字符串里面不能包含空字符,否则最先被程序读入的空字符将被误认为是字符串结尾,这些限制使得C字符串只能保存文本数据,而不能保存像图片、音频、视频、压缩文件这样的二进制数据。
解决
sds
SDS(simple dynamid string )的 API都是二进制安全的(binary-safe),所有SDS API都会以处理二进制的方式来处理SDS存放在buf数组里的数据,程序不会对其中的数据做任何限制、过滤、或者假设,数据在写入时是什么样的,它被读 取时就是什么样。
通过使用二进制安全的SDS,而不是C字符串,使得Redis不仅可以保存文本数据,还可以保存任意格式的二进制数据。
SDS使用len属性的值而不是空字符来判断字符串是否结束
redis批量命令
批量get/set(multi get/set)
命令
string
mget
mset
hash
hmset
hmget
代码
redis.clients.jedis.Jedis#mget
管道(pipelining)
使用
客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。服务端处理命令,并将结果返回给客户端。
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。
pipeline就是把一组命令进行打包,然后一次性通过网络发送到Redis。同时将执行的结果批量的返回回来. 使用管道发送命令时,服务器将被迫回复一个队列答复,占用很多内存。所以,如果你需要发送大量的命令,最好是把他们按照合理数量分批次的处理,例如10K的命令,读回复,然后再发送另一个10k的命令,等等。
代码
redis.clients.jedis.Pipeline
父类
redis.clients.jedis.MultiKeyPipelineBase
命令
安装nc命令
yum install nc
nc打包多个命令
(printf "PING\r\nPING\r\nPING\r\n") | nc localhost 6379
事务(transaction)
命令
代码
基于事务的管道(transaction in pipelining)
在Redis中,管道是通过RESP,即redis协议来实现的,它允许在一个消息包中按照指定格式传递多个命令。而事务是通过命令实现的,因此管道和事务之间并不冲突,事务可以承载与管道之上。在某些场景,需要在一次请求处理中发起多次事务的场景下,通过引入管道,可以获得略高于单独执行多次事务的性能,但是两者的差距非常小,小到可以忽略。
代码
redis在项目中是怎么用的
分布式锁
主要利用redis的setnx命令进行,setnx:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0。
key
warehouseCode+itemCode
入库
出库
占用
释放
缓存
库存
基础数据
仓库/货主/覆盖区域
字典
地区
限时业务的运用
redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景
缓存与数据库的一致性(20210511)
写时更新
介绍
当我们往数据库写数据的时候我们去更新缓存,包括先更新缓存再更新数据库和先更新数据库再更新缓存。
缺点
效率问题
如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。
线程安全性问题
同时有请求A和请求B进行更新操作,那么会出现 (1)线程A更新了数据库 (2)线程B更新了数据库 (3)线程B更新了缓存 (4)线程A更新了缓存。这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。
写时删除,读时更新
介绍
当我们往数据库写数据的时候我们直接删除缓存,然后其他请求读数据的时候更新缓存。包括先删除缓存再更新数据和先更新数据库再删除缓存。
分类
先更新数据库在删除缓存
问题
问题一、如果在高并发的场景下,会出现数据库与缓存数据不一致
场景
1、缓存刚好失效 线程 A 查询数据库,得一个旧值
2、线程 B 将新值写入数据库
3、线程 B 删除缓存
4、线程 A 将查到的旧值写入缓存
出现概率极低
需要线程A读操作必需在B线程写操作前进入数据库操作,而又要晚于B写操作更新缓存,所有的这些条件都具备的概率基本并不大
解决
设置缓存的过期时间,这样可以达到最终一致性
问题二、如果删除缓存失败或更新数据库失败了会怎样?
第一步操作数据库成功,第二步删除缓存失败,会导致数据库里是新数据,而缓存里是旧数据
解决
将需要删除的 key 发送到消息队列中 自己消费消息,获得需要删除的 key 不断重试删除操作,直到成功
第一步操作数据库就失败了,第二步更新缓存不会执行,不会出现数据不一致。
总结
在高并发下相对出现数据不一致问题概率很低,但在原子性被破坏时(删除缓存失败或更新数据库失败)会出现数据一致性问题
解决方案就是要给KEY设置过期时间
先删除缓存再更新数据
问题
问题一、如果在高并发的场景下,会出现数据库与缓存数据不一致
场景
1、线程 A 删除了缓存 线程 B 查询,发现缓存已不存在
2、线程 B 去数据库查询得到旧值
3、线程 B 将旧值写入缓存
4、线程 A 将新值写入数据库
解决
设置缓存的过期时间,这样可以达到最终一致性
问题二、如果删除缓存失败或更新数据库失败了会怎样?
第一步删除缓存成功,第二步更新数据库失败,数据库和缓存的数据还是一致的。
第一步删除缓存就失败了,第二步更新数据库不会去执行,数据库和缓存的数据还是一致的。
总结
并不会导致数据不一致问题
总结
在高并发下相对更容易出现数据不一致问题,但在原子性被破坏时(删除缓存失败或更新数据库失败)并不会出现数据一致性问题
解决方案就是要给KEY设置过期时间
其他解决方案
延时双删策略
1、先淘汰缓存
2、再写数据库
3、休眠1秒/写数据成功之后
要造成脏缓存,就需要在缓存被删除后,数据库被更新前有请求读取到了旧数据并更新了缓存,那么这边睡眠一秒后再次删除缓存就可以把这个短暂的时间间隔内产生的脏缓存再次删除掉。
4、再次淘汰缓存.
阿里canal方案
启动一个订阅程序去订阅数据库的binlog,获得需要操作的数据。在应用程序中,另起一段程序,获得这个订阅程序传来的信息,进行删除缓存操作。
原理图
LinkedIn的DataBus
其原理和阿里的Canal一致
内存回收
淘汰策略
Redis 的内存淘汰策略,是指当内存使用达到最大内存极限时,需要使用淘汰算法来 决定清理掉哪些数据,以保证新数据的存入
redis.conf 参数配置:# maxmemory <bytes>
64 位系统不限制内存,32 位系统最多使 用 3GB 内存
动态修改:config set maxmemory 2GB
LRU
Least Recently Used:最近最少使用
volatile-lru
在带有过期时间的键,中删除最近最少使用的
allkeys-lru
在所有带有过期时间的Key中,删除最近最少使用的
Redis优化过:
如果淘汰策略是 LRU,则根据配置的采样值 maxmemory_samples(默认是 5 个), 随机从数据库中选择 m 个 key, 淘汰其中热度最低的 key 对应的缓存数据
LFU
Least Frequently Used,最不常用(最近使用频次最少的),4.0 版本新增
volatile-lfu
在带有过期时间的键中删除最不常用的。
allkeys-lfu
在所有的键中选择最不常用的,不管数据有没有设置超时属性。
Rondom
随机删除
volatile-random
在带有过期时间的键中随机删除
allkeys-random
随机删除所有键,直到腾出足够内存为止。
noeviction
默认策略,不会删除任何数据,达到内存最大后,返回错OOM,只响应读操作
volatile-ttl
根据键值对象的 ttl 属性,删除最近将要过期数据。如果没有,回退到 noeviction 策略
动态修改淘汰策略
config set maxmemory-policy volatile-lru
默认推荐使用:建议使用 volatile-lru,在保证正常服务的情况下,优先删除最近最少使用的 key。
思考如何基于一个数据结构实现LRU算法:
LinkedHashMap是有序的,且默认为插入顺序,先进入在前,后进去的在后面,
继承LinkedHashMap并重写removeEldestEntry方法
过期策略
定时过期
每个设置过期时间的 key 都需要创建一个定时器,到过期时间就会立即清除
效率很高,但是key很多的时候 也创建了大量的定时器,对内存很友好,占用大量的 CPU 资源去处理过期的 数据
惰性过期(被动淘汰)
只有当访问一个 key 时,才会判断该 key 是否已过期,过期则清除
该策略可以最 大化地节省 CPU 资源,却对内存非常不友好,极端情况可能出现大量的过期 key 没有再 次被访问,从而不会被清除,占用大量内存
定期过期
每隔一定的时间,会扫描一定数量的数据库的 expires 字典中一定数量的 key,并清 除其中已过期的 key。该策略是前两者的一个折中方案
缓存三大问题
缓存穿透(缓存和数据库都不存在)
概念
指查询一个根本不存在的数据,缓存层和存储层都不会命中
缓存穿透将导致不存在的数据每次请求都要到存储层去查询,失去了缓存保护后端的意义
原因
自身业务代码或者数据出现问题;
一些恶意攻击、爬虫等造成大量空命中
解决方法
缓存空对象
解决
缺点
1、空值做了缓存,意味着缓存层中存了更多的键,需要更多内存空间。
比较有效的方法是针对这类数据设置一个较短的过期时间。
比较有效的方法是针对这类数据设置一个较短的过期时间。
2、缓存层和存储层的数据会有一段时间窗口的不一致,可能会对业务有一定影响。
布隆过滤器
概念
是一种空间利用率较高的概率型数据结构,用来测试一个元素是否在集合中。但是存在一定可能,导致结果误判。即元素不在集合中,查询结果却返回元素在集合中。
原理
当一个元素被加入集合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,我们只要看看这些点是不是都是1就(大约)知道集合中有没有它了:如果这些点有任何一个0,则被检元素一定不存在;如果都是1,则被检元素很可能存在
Bloom Filter跟单哈希函数Bit-Map不同之处在于:Bloom Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率。
原理图
优点
二进制组成的数组,占用内存极少,并且插入和查询速度都足够快
缺点
随着数据的增加,误判率会增加
无法判断数据一定存在
无法删除数据
缓存击穿(某个热点key失效)
概念
缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,
又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
解决方案
设置热点数据永远不过期。
加互斥锁
在缓存失效后,通过互斥锁或者队列来控制读数据写缓存的线程数量,比如某个key只允许一个线程查询数据和写缓存,其他线程等待。这种方式会阻塞其他的线程,此时系统的吞吐量会下降
缓存雪崩(大量key同时过期)
概念
Redis中大量的key几乎同时过期,然后大量并发查询穿过redis击打到底层数据库上,此时数据库层的负载压力会骤增
解决方案
在可接受的时间范围内随机设置key的过期时间,分散key的过期时间,以防止大量的key在同一时刻过期;
对于一定要在固定时间让key失效的场景(例如每日12点准时更新所有最新排名),可以在固定的失效时间时在接口服务端设置随机延时,将请求的时间打散,让一部分查询先将数据缓存起来;
延长热点key的过期时间或者设置永不过期
常见问题
ERR SELECT is not allowed in cluster mode
在集群模式下这个配置是不起作用的,集群客户端是不支持多数据库db的,只有一个数据库默认是SELECT 0;
redis在单机模式下redis.conf配置文件中默认的数据库数量是16个
集群slave从节点默认是不支持读写操作的,但是在执行过readonly命令后可以执行读操作
发生异常错误信息(redis缓存处理序列化时)
问题
详细
原因
实体entity未被序列化
解决
配置序列化
无法读取json Could not read JSON: Invalid UTF-32 character 0x5b21636f
问题
详细
原因
使用set方法错误,使用4个参数的set方法,带过期时间
解决
把 redisTemplate.opsForValue().set(REDIS_USER_KEY + id, new NullEntity(), 60);
修改为 redisTemplate.opsForValue().set(REDIS_USER_KEY + id, new NullEntity(), 60, TimeUnit.SECONDS);
修改为 redisTemplate.opsForValue().set(REDIS_USER_KEY + id, new NullEntity(), 60, TimeUnit.SECONDS);
redisssion加锁失败 Operation against a key holding the wrong kind of value
问题
详细
原因
WRONGTYPE Operation against a key holding the wrong kind of value tells that another object by the same key is stored but with different type.
有重复的key
解决
换个key即可
redis客户端
客户端连接工具
redis desktop manager
1、安装
2、使用
连接
connetc to redis server
name 名称
host 主机
port端口
auth 密码
3、打开控制台
ctr+T
get AUTH:STATIC:TENANT:CODE:P001
4、页面上参数
子主题
5、打开0数据库
效果
redis-client中国红
登录
使用
查找key
更新key
复制key
java连接客户端
spring data redis(20210305)
注解
常用注解
Cacheable
缓存
CacheEvict
清除
CachePut
更新
实现原理
aop
RedisTemplate/StringRedisTemplate
jedis
分布式锁
普通实现
lua脚本实现
集群
哨兵模式
集群模式
lua脚本(20210305)
简介
Lua 是一种轻量小巧的脚本语言,用标准C语言编写并以源代码形式开放, 其设计目的是为
了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能
了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能
下载地址
http://www.lua.org/download.html
linux安装
解压
编译
make all test
查看版本信息
lua -v
使用
脚本式编程
测试hello world
交互式编程
实现分布式锁
安全
禁止危险命令
相关命令
keys *
在小数据量情况下使用没什么问题,数据量大会导致 Redis 锁住及 CPU 飙升,在生产环境建议禁用或者重命名!
flushdb
删除Redis中当前所在数据库中的所有记录,并且该命令是原子性的,不会终止执行,一旦执行,将不会执行失败
flushall
删除Redis中所有数据库中的所有记录,并且该命令是原子性的,不会终止执行,一旦执行,将不会执行失败。
config
客户端可修改 Redis 配置
解决方案
命令禁用
rename-command ,修改即可完成命令禁用
效果
重命名命令
效果
密码
配置文件配置redis.conf
requirepass password
requirepass 123456
登录
使用命令配置
config set requirepass 123456
命令(20210306)
script脚本命令
eval
参考
http://doc.redisfans.com/script/eval.html#lua-redis
语法
EVAL script numkeys key [key ...] arg [arg ...]
sript
lua脚本
numkeys
用于指定键名参数的个数
key [key ...]
在脚本中所用到的那些 Redis 键(key),为一个数组,可通过KEYS[1] , KEYS[2]访问
arg [arg ...]
通过全局变量 ARGV 数组访问,可通过ARGV[1] 、 ARGV[2]访问
使用
执行函数
redis.call()
redis.pcall()
在 Lua 数据类型和 Redis 数据类型之间转换
示例
EVALSHA
介绍
1)EVAL 命令要求你在每次执行脚本的时候都发送一次脚本主体(script body)。
2)Redis 有一个内部的缓存机制,因此它不会每次都重新编译脚本,不过在很多场合,付出无谓的带宽来传送脚本主体并不是最佳选择。
3)为了减少带宽的消耗, Redis 实现了EVALSHA 命令,它的作用和 EVAL 一样,都用于对脚本求值,但它接受的第一个参数不是脚本,而是脚本的 SHA1 摘要
返回结果
如果有给定的 SHA1 校验和所指定的脚本,那么执行这个脚本
没有,那么它返回一个特殊的错误,提醒用户使用 EVAL 代替 EVALSHA
测试
其他脚本命令
判断脚本是否存在
SCRIPT EXISTS script [script ...]
刷新脚本缓存
SCRIPT FLUSH
杀死正在执行的脚本
SCRIPT KILL
加载脚本
SCRIPT LOAD script
Key(键)
scan
参考
http://doc.redisfans.com/key/scan.html
简介
SCAN 命令是一个基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标,
用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
语法
SCAN cursor [MATCH pattern] [COUNT count]
使用
返回值
返回值1
用于进行下一次迭代的新游标
返回值2
包含了所有被迭代的元素
不加参数
scan curor
match选项
进行模式匹配,返回符合条件的元素
count选项
每次迭代中应该从数据集里返回多少元素
COUNT 参数的默认值为 10
完整遍历
以 0 作为游标开始一次新的迭代, 一直调用 SCAN 命令, 直到命令返回游标 0
ttl
简介
以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。
语法
TTL key
返回值
当 key 不存在,或者 key 没有设置剩余生存时间时,命令都返回 -1
使用
keys
介绍
查找所有符合给定模式pattern(正则表达式)的 key 。
时间复杂度为O(N),N为数据库里面key的数量。
速度极快,在一百万的key数据库中查询时间大约是40毫秒。
语法
KEYS pattern
使用
Server(服务器)
config
用于取得运行中的 Redis 服务器的配置参数(configuration parameters)
CONFIG GET parameter
动态地调整 Redis 服务器的配置(configuration)而无须重启
CONFIG SET parameter value
对启动 Redis 服务器时所指定的 redis.conf 文件进行改写,即保存到redis.conf文件中
CONFIG REWRITE
重置 INFO 命令中的某些统计数据
CONFIG RESETSTAT
持久化方式
AOF
默认不开启
AOF 采用日志的形式来记录每个写操作,并追加到文件中。
开启后,执行更改 Redis 数据的命令时,
就会把命令写入到 AOF 文件中。
Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复 工作
开启后,执行更改 Redis 数据的命令时,
就会把命令写入到 AOF 文件中。
Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复 工作
redis.conf
# 开关appendonly no
appendfilename "appendonly.aof"
带来的问题:
数据都是实时持久化到磁盘吗?
不是的,是先进入了系统的缓存区,硬盘缓存区
appendfsync
everysec
表示每秒执行一次 fsync,可能会导致丢失这 1s 数据。通常选择 everysec , 兼顾安全性和效率。
always
表示每次写入都执行 fsync,以保证数据同步到磁盘,效率很低;
no
表示不执行 fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全;
文件越来越大,怎么办?
如 set abc 666,执行 1000 次,结果都是 abc=666。
以使用命令 bgrewriteaof 来重写
当 AOF 文件的大小超过所设定的阈值 时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集
auto-aof-rewrite-percentage 100
默认值为 100。aof 自动重写配置,当目前 aof 文件大小超过上一次重写的 aof 文件大小的 百分之多少进行重写,即当 aof 文件增长到一定大小的时候,Redis 能够调用 bgrewriteaof 对日志文件进行重写。当前 AOF 文件大小是上次日志重写得到 AOF 文件大小的二倍(设 置为 100)时,自动启动新的日志重写过程。
auto-aof-rewrite-min-size 64mb
默认 64M。设置允许重写的最小 aof 文件大小,避免了达到约定百分比但尺寸仍然很小的 情况还要重写。
重写过程中,AOF 文件被更改了怎么办?
no-appendfsync-on-rewrite
设置为 yes 表示 rewrite 期间对新写操作不 fsync, 暂时存在内存中,等 rewrite 完成后再写入,默认为 no,建议修改为 yes。Linux 的默认 fsync 策略是 30 秒。可能丢失 30 秒数据。
aof-load-truncated
aof 文件可能在尾部是不完整的,当 redis 启动的时候,aof 文件的数据被载入内存。重启 可能发生在 redis 所在的主机操作系统宕机后,尤其在 ext4 文件系统没有加上 data=ordered 选项,出现这种现象。redis 宕机或者异常终止不会造成尾部不完整现象,可以选择让 redis 退出,或者导入尽可能多的数据。
如果选择的是 yes,当截断的 aof 文件被导入的时候, 会自动发布一个 log 给客户端然后 load。如果是 no,用户必须手动 redis-check-aof 修复 AOF 文件才可以。默认值为 yes。
优点:
AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步 一次,Redis 最多也就丢失 1 秒的数据而已。
对于具有相同数据的的 Redis,AOF 文件通常会比 RDF 文件体积更大(RDB 存的是数据快照
RDB快照
默认的持久化策略,生成dump.rdb
RDB 触发
配置规则触发 redis.conf
save 900 1 # 900 秒内至少有一个 key 被修改(包括添加)不使用时 直接注释
配置保存文件路径,是否开启压缩
手动触发
save
save 在生成快照的时候会阻塞当前 Redis 服务器, Redis 不能处理其他命令。如果 内存中的数据比较多,会造成 Redis 长时间的阻塞,生产环境不建议使用
bgsave
执行 bgsave 时,Redis 会在后台异步进行快照操作,快照同时还可以响应客户端请 求
Redis 进程执行 fork 操作创建子进程(copy-on-write),RDB 持久化 过程由子进程负责,完成后自动结束
shutdown 触发,保证服务器正常关闭
flushall,RDB 文件是空的,没什么意义
练习操作命令
优势:
1、RDB 是一个非常紧凑(compact)的文件,它保存了 redis 在某个时间点上的数据 集。这种文件非常适合用于进行备份和灾难恢复
2、生成 RDB 文件的时候,redis 主进程会 fork()一个子进程来处理所有保存工作,主 进程不需要进行任何磁盘 IO 操作
3、RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快
劣势:
RDB 方式数据没办法做到实时持久化/秒级持久化。因为 bgsave 每次运行都要 执行 fork 操作创建子进程,频繁执行成本过高
在一定间隔时间做一次备份,所以如果 redis 意外 down 掉的话,就会丢失最后 一次快照之后的所有修改(数据有丢失)
AOF和RDB的选择
如果可以忍受一小段时间内数据的丢失,毫无疑问使用 RDB 是最好的,定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要 比 AOF 恢复的速度要快
否则就使用 AOF 重写。但是一般情况下建议不要单独使用某一种持久化机制,而 是应该两种一起用,在这种情况下,当 redis 重启的时候会优先载入 AOF 文件来恢复原始 的数据,因为在通常情况下 AOF 文件保存的数据集要比 RDB 文件保存的数据集要完整。
数据类型
数据类型
String
字符串
set name kklt
get name
语法
set
SET key value [EX seconds] [PX milliseconds] [NX|XX]
get
GET key
当 key 不存在时,返回 nil ,否则,返回 key 的值。
如果 key 不是字符串类型,那么返回一个错误。
mset
mget
Hash
哈希
HSET website google www.google.com baidu www.baidu.com
HGET website google
hash的结构是:key field value
包含键值对的无序散列表。value 只能是字符串,不能嵌套其他类型
set
集合
SADD bbs aa bb cc
SMEMBERS bbs
zset
有序集合
ZADD page_rank 10 google.com
sorted set,有序的 set,每个元素有个 score。 score 相同时,按照 key 的 ASCII 码排序
List
列表
LPUSH mylist a b c
LRANGE mylist 0 -1
查看mylist中的所有数据
Hyperloglog
Geo
Streams
应用场景
String类型
热点数据缓存
对象缓存,全页缓存。
分布式锁
STRING 类型 setnx 方法,只有不存在时才能添加成功,返回 true。
分布式 Session
全局 ID
INT 类型,INCRBY,利用原子性
计数器
INT 类型,INCR 方法
文章的阅读量,微博点赞数,允许一定的延迟,先写入 Redis 再定时同步到 数据库
限流
INT 类型,INCR 方法
以访问者的 IP 和其他信息作为 key,访问一次增加一次计数,超过次数则返回 false。
位统计
String 类型的 BITCOUNT(1.6.6 的 bitmap 数据结构介绍)。
问题:String类型如何存一个对象
利用分层:mset student:1:sno GP16666 student:1:sname 沐风 student:1:company 腾讯
代表的意思是: student:1:sno 为key GP16666 为value
缺点:key 太长,占用的空间太多
基础信息的存储
仓库
货主
库存存储
账面库存
库存值
仓库+商品+库存类型
mcsp:stc:inv:stock:OZIW005:21051030Z00143:1
锁定值
仓库+商品+库存类型
mcsp:stc:inv:stocklock:ZNKOW0102:21061110000905:1
销售库存
库存值
仓库+商品+分区类型
mcsp:stc:inv:sales:IQHTW0001:21063210000025:SELF
锁定值
仓库+商品+分区类型
mcsp:stc:inv:saleslock:MCPRW0001:31022210004823:SELF
hash:
存储字符串,Hash 与 String 的主要区别?
把所有相关的值聚集到一个 key 中,节省内存空间
只使用一个 key,减少 key 冲突
当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU 的消耗
不适合的场景:
1、Field 不能单独设置过期时间
2、没有 bit 操作
3、需要考虑数据量分布的问题(value 值非常大的时候,无法分布到多个节点)
String 可以做的事情,Hash 都可以做。
购物车
List
存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色
场景:
消息队列
用户消息时间线 timeline
Set
随机获取元素 spop myset
点赞、签到、打卡
商品标签
商品筛选
差集
sdiff set1 set2
交集
sinter set1 set2
并集
sunion set1 set2
黑名单列表
smembers forbidden_list
zset
排行榜
0 条评论
下一页