Redis Contents
Redis
Redis 一开始是作为缓存存在的,当多用户同时访问,导致服务器处理不过来
1 Redis 基础
1.1 Redis入门
现实问题:
- 海量用户
- 高并发
罪魁祸首——关系型数据库:
- 性能瓶颈:磁盘IO性能低下
- 扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
解决思路:
- 降低磁盘IO次数,越低越好 —— 内存存储
- 去除数据间的关系,越简单越好 —— 不存储关系,仅存储数据
1.1.1 NoSQL
即Not-OnlySQL(泛指非关系型的数据库),作为关系型数据库的补充。
作用:应用对于海量用户和海量数据前提吓得数据处理问题。
特征:
- 可扩容,可伸缩
- 大数据量下得高性能
- 灵活得数据模型(需要能兼容,非关系型数据库是关系型数据库的一个补充,数据还是要存到磁盘上的)
- 高可用
常见Nosql数据库:
- Redis
- memcache
- HBase
- MongoDB
解决方案(电商场景)
1.1.2 Redis简介
概念:Redis(REmote DIctinary Server)是用C语言开发的一个开源的高性能键值对 (key-value)数据库
特征:
- 数据间没有必然的关联关系
- 内部采用单线程机制进行工作(操作原子性,保证了安全性)
- 高性能。官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s。
- 多数据类型支持:string(字符串类型)、list(列表类型)、hash(散列类型)、set(集合类型)、sorted_set(有序集合类型)
- 持久化支持。可以进行数据灾难恢复
Redis的应用
- 为热点数据加速查询(主要场景)、如热点商品、热点新闻、热点资讯、推广类等提高访问量信息等。
- 任务队列、如秒杀、抢购、购票等
- 即时信息查询,如各位排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等
- 时效性信息控制,如验证码控制,投票控制等
- 分布式数据共享,如分布式集群构架中的session分离
- 消息队列
- 分布式锁
1.1.3 Redis的基本操作
命令行模式工具使用思考
- 功能性命令
- 添加:
set key value
- 查找:
get key
找不到会显示nil
- 添加:
- 清除屏幕信息:
clear
- 帮助信息查阅:
help
- 退出指令:
exit
esc
1.2 数据类型
1.2.1 数据存储类型介绍
业务数据的特殊性,作为缓存使用:
- 原始业务功能设计:秒杀、618活动、双十一活动、排队购票
- 运营平台监控到的突发高频访问数据(如热搜):突发市政要闻,被强势关注围观
- 高频、复杂的统计数据:在线人数、投票排行榜
附加功能,系统功能优化或升级:
- 单服务器升级集群
- Session管理
- Token管理
Redis 数据类型(5种常用),按照Redis赋予的使命—即业务要求,前人总结出了这5种常用数据类型,可以类比Java的几种数据类型来加深理解:
- string --> String
- hash --> Hashmap
- list --> LinkList
- set --> HashSet
- sorted_set --> TreeSet
1.2.2 String
redis 数据存储格式
- redis自身是一个Map,其中所有的数据都是采用key:value的形式存储
- 数据类型指的是存储的数据的类型,也就是value部分的类型,key部分永远都是字符串
String 类型
- 存储的数据:单个数据,最贱的数据存储类型,也是最常用的数据存储类型
- 存储数据的格式:一个存储空间保存一个数据
- 存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
String 类型数据的基本操作
- 添加/修改数据:
set key value
- 获取数据:
get key
- 删除数据:
del key
- 添加/修改多个数据:
mset key1 valueq key2 value2 …
m表示multiple - 获取多个数据:
mget key1 key2 …
- 获取数据字符个数(字符串长度):
strlen key
- 追加信息到原始信息后部(如果原始信息存在就追加,否则新建):
append key value
指令执行的步骤:从服务器发送到redis,redis进行指令处理,最后返回服务器。因此指令越多可能造成越多的时间消耗,需要衡量单指令和多指令:
String类型数据的扩展操作
业务场景
大型企业级应用中,数据量越来越大,一个表中存储不能无限制的添加新纪录,需要分表存储,甚至需要分库存储)。分表操作是基本操作,使用多张表存储同类型数据,但是对应的主键id必须保证统一性,不能重复。Oracle数据库具有sequence设定,可以解决该问题,但是MySQL数据库并不具有类似的机制,那么如何解决?
解决方案
- 设置数值数据增加指定范围的值
- 设置数值数据减少指定范围的值
incr key
incrby key increment // increment 可正可负
incrbyfloat key increment
decr key
decrby key increment
String作为数值操作:
- string在redis内部存储默认就是一个字符串,当遇到增减类操作
incr
,decr
时会转成数值型进行计算。 - redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响。
- 注意:按数值进行操作的数据,如果原始数据不能转成数值,或超过了redis数值上线范围,将会报错。9223372036854775807 (java中long型数据最大值,Long.MAX_VALUE)
业务场景
- 场景一:“最强女生”,启动海选投票,只能通过微信投票,每个微信号每4个小时只能投1票。(将投过票的用户微信号ID存储到数据库中,并设置4小时时限,限制在微信号存在时不可以投票,当时间结束,将数据库中该ID删除,就可以继续投票了)
- 场景二:电商商家开启热门商品推荐,热门商品不能一直处于热门期,每种商品热门期维持3天,3天后自动取消热门
- 场景三:新闻网站会出现热点新闻,热点新闻最大的特征是对时效性,如何自动控制热点新闻的时效性。
解决:设置数据的生命周期
setex key seconds value
psetex key milliseconds value
业务场景:主页高频访问信息显示控制,例如新浪微博大V主页显示粉丝数与微博数量
1.2.3 Hash
存储的困惑
对象类数据的存储如果具有较为频繁的更新需求操作会显得笨重
hash类型:
- 新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
- 需要的内存结构:一个存储空间保存多少个键值对数据
- hash类型:底层使用哈希表结构实现数据存储
hash类型数据的基本操作:
- 添加/修改数据:
hset key field value
- 获取数据:
hget key field
hgetall key
- 删除数据:
hdel key field1 [field2]
- 添加/修改多个数据:
hmset key field1 value1 field2 calue2
- 获取多个数据:
hmget key field1 field2 …
- 获取哈希表中字段的数量:
hlen key
- 获取哈希表中是否存在指定的字段(1表示成功,0表示失败):
hexists key field
hash类型数据扩展操作
- 获取哈希表中所有的字段名和字段值:
hkeys key
hvals key
- 设置指定字段的数值数据增加指定范围的值:
hincrby key field increment
hincrbyfloat key field increment
hash类型数据操作的注意事项:
- hash类型下的value只能存储字符串,不允许存储其他类型数据,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
- 每个hash可以存储 2 32 − 1 2^{32}-1 232−1个键值对
- hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初中不是为了存储大量对象而设计的,切记不可滥用,更不可以将hash作为对象列表使用【可以存对象,不要滥用】
- hgetall操作可以获取全部属性,如果内部fiekd过多,遍历整体数据效率就会很低,有可能成为数据访问瓶颈 【用哪个拿哪个,不要全拿】
应用:电商购物车
当前设计是否加速了购物车的呈现?
当前仅仅是将数据存储到redis中,并没有起到加速的所用,商品信息还需要二次查询数据库
- 每条购物车中的商品记录保存成两条field
- field1 专用于保存购买数量
1、命名格式:商品id:nums
2、保存数据:数值 - field2 专用于保存购物车中显示的信息,包含文字描述,图片地址,所属商家信息等(独立hash)
1、命名格式:商品id:info
2、保存数据:json
可以看出来又具有了大量的信息重复,所以我们可以把field2的内容变成一个固定的hash
最终解决方法:将公共的商品信息部分用该指令添加:hsetnx key field value
,相当于在set添加时做了一层判定,如果filed有值,不操作;没有值,才添加。
hash应用场景二:商家
解决方案
- 以商家id作为key
- 将参与抢购的商品id作为field
- 将参与抢购的商品数量作为对应的value:边抢数量边减,通过加负数来减,用
hincrby p01 c100 -20
- 抢购时使用降至的方式控制产品数量
String 和 hash 的对象存储:
String用存储对象,hash存储(对象的某个属性可以单独拿出来改)
1.2.4 list
- 数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
- 需要的存储数据:一个存储空间保存多个数据,且通过数据可以体现进入顺序
- list类型:保存多个数据,底层使用双向链表存储结构实现
list 类型数据基本操作
-
添加/修改数据
lpush key value1 [value2] … rpush key value1 [value2] …
-
获取数据(右边进,左边查,就和插入顺序看起来是一样的)
lrange key start stop // 0 -1 可以从头查到最后一个元素 lindex key index // 索引 llen key
-
删除并移除数据
lpop key rpop key
-
list 类型数组扩展操作,阻塞式数据获取:规定时间内获取并移除数据,阻塞式获取,获取值如果还没有的时候可以等,如果有值就可以获取到。(给定一个队列和等待时间,如果在等待时间内没有任务就等待,有任务就马上执行,像是一个任务队列)
blpop key1 [key2] timeout brpop key1 [key2] timeout
业务场景:
微信朋友圈点赞,有一个点赞顺序,将点赞用户的ID按照先后顺序入队;当此时有一个人撤销点赞,需要从队列中间删除元素,此时可以
lrem key count value
(由于list中元素可以重复,因此可以指定删除的个数)redis引用与具有操作先后顺序的数据控制
list类型数据操作注意事项
- list 中保存的数据都是string类型的,数据总容量式有限的,最多 2 32 − 1 2^{32}-1 232−1个元素(4294967295)
- list具有索引的概念,但是操作数据时候通常以队列的形式进行入队出队操作,或以栈的形式进入栈出栈的操作
- 获取全部数据操作结束索引设置为
-1
- list 可以对数据进行分页操作,通过第一页的信息来自list,第2页及更多的信息通过数据库的形式加载
list类型应用场景
- 业务场景
- twitter、新浪微博、腾讯微博中个人用于的关注列表需要按照用户的关注顺序进行展示,粉丝列表需要将最近关注的粉丝列在前面
- 新闻、资讯类网站如何将最新的新闻或资讯按照发生的事件顺序展示
- 企业运营过程中,系统将产生出大量的运营数据,如何保障多台服务器操作日志的统一顺序输出?(将多个服务器的日志信息都写入redis中,将所有服务器的工作日志都写到一个数据库中,方便运维人员进行检错查询)
- 解决方案【redis消息聚集–利用消息顺序性】
- 依赖list的数据具有顺序的特征对信息进行管理
- 使用队列模型解决多路信息汇总合并的问题
- 使用栈模型解决最新消息的问题
redis可以查询最新的消息
1.2.5 Set
-
新的存储需求:存储大量的数据,在查询方面提供更高的效率
-
需要的存储结构:能够保存大量的数据,搞笑的内部存储机制,便于查询
-
set类型:与hash存储结构完全相同,仅存储键,不存储值(nil),并且值式不允许重复的
set 数据的基本操作:
- 添加数据:
sadd key menber1 [menber2]
- 获取全部:
smenmbers key
- 删除数据:
srem key member1 [member2]
remove - 获取集合数量总量:
scard key
- 判断是否存在:
sismember key member
set 数据的扩展操作
-
业务场景:
每位用户首次使用进入头条时候会设置3项爱好的内容,但是后期为了增加用户的活跃度,兴趣点,必须让用户对其他信息类别逐渐产生兴趣,增加客户留存度,如何实现?
-
业务分析:
新用户设置的三个爱好也可能是随便选的,平台不会只给用户推送自己喜爱的专题文章,可能需要推送别的专题的,那么,可以随机向用户推送部分其他专题信息,然后只要他点开过,之后就可以一直推送相关的了。
- 系统分析出各个分类的最新或最热点信息条目并组织成set集合
- 随机挑选其中部分信息
- 配合用户关注信息分类中的热点信息组织展示的全信息集合
-
解决方案
- 随机获取集合中指定数量的数据
srandmember key [count]
- 随机获取集合中某个数据并将该数据移除
spop key
redis可以随机查询数据
- 随机获取集合中指定数量的数据
-
业务场景
- 脉脉为了促进用户间的交流,保障业务成单率的提升,需要让每位用户拥有大量的好友,事实上职场新人不具有更多的职场好友,如何快速为用户积累更多的好友?【共同好友】
- 新浪微博为了增加用户热度,提高用户留存性,需要微博用户在关注更多的人,以此获得更多的信息或热门话题,如何提高用户关注他人的总量?
- QQ新用户入网年龄越来越低,这些用户的朋友圈交际圈非常小,往往集中在一所学校甚至一个班级中,如何帮助用户快速积累好友用户带来更多的活跃度?
- 微信公众号是微信信息流通的渠道之一,增加用户关注的公众号成为提高用户活跃度的一种方式,如何帮助用户积累更多关注的公众号?
- 美团外卖为了提升成单量,必须帮助用户挖掘美食需求,如何推荐给用户最适合自己的美食?
-
解决方案
-
求两个集合的交、并、差集
sinter key1 [key2] # set inter sunion key1 [key2] # set union sdiff key1 [key2] # set difference
-
求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2] sunionstore destination key1 [key2] sdiffstore destination key1 [key2]
-
将指定数据从原始集合移动到目标集合中
smove source destination member
redis应用于同类信息的关联搜索,二度关联搜索,深度关联搜索
显示共同关注(一度)
显示共同好友(一度)
由用户A出发,获取到好友用户B的好友信息列表(一度)
由用户A出发,获取到好友用户B的购物清单列表(二度)
由用户A出发,获取到好友用户B的游戏充值列表(二度) -
Set类型数据操作的注意事项
- set类型不允许数据重复【去重】,如果添加的数据在set中已经存在,将只保留一份
- set虽然与hash的存储结构相同,但是无法启用hash中存储值的空间
set 应用场景
-
业务场景
集团公司共具有12000名员工,内部OA系统中具有700多个角色,3000多个业务操作,23000多种数据,每位员工具有一个或多个角色,如何快速进行业务操作的权限校验?
-
解决方案
-
依赖set集合数据不重复的特征,依赖set集合hash存储结构特征完成数据过滤与快速查询
-
根据用户id获取用户所有角色心
-
根据用户所有角色获取用户所有操作权限放入set集合
-
根据用户所有角色获取用户所有数据全选放入set集合
-
【set部分补充】https://blog.csdn.net/qmqm33/article/details/105619546
1.2.6 sorted set
用于排序后再查询。在set的基础上,增加一个值用于排序。
有序集合数据的基本操作:
-
添加数据
zadd key score1 member1 [score2 member2]
-
获取全部数据
zrange key start stop [WITHSCORES] zrevrange key start stop [WITHSCORES]
-
删除数据
zrem key member [member …]
-
按条件获取数据
zrangebyscore key min max [WITHSCORES] [LIMIT] # limit 查询结果的范围 zrevrangebyscore key max min [WITHSCORES]
-
条件删除
zremrangebyrank key start stop # 按照大小顺序的索引删除,start、end都是和索引相关的 zremrangebyscore key min max # min max 描述条件,和数据比较
注意:
- min与max用于限定搜索查询的条件
- start与stop用于限定查询范围,作用于索引,表示开始和结束索引
- offset与count用于限定查询范围,作用于查询结果,表示开始位置和数据总量
-
获取集合数据总量
zcard key zcount key min max
-
集合交、并操作
zinterstore destination numkeys key [key …] zunionstore destination numkeys key [key …]
sorted_set 数据的扩展操作
P28、29、30 排序
1.3 通用命令
key特征:key是一个字符串,通过key获得redis中保存的数据
key应该设计那些操作?
-
对于key自身状态的相关操作,例如:删除,判定存在,获取类型等
-
删除指定key:
del key
-
获取key是否存在:
exists key
-
获取key的类型:
type key
-
-
对于key有效性控制相关操作,例如:有效期设定,判定是否有效,有效状态的切换等
-
为指定key设置有效期
expire key seconds # 设置key的有效期(秒) pexpire key milliseconds # p-expire:设置剩余有效期(毫秒) expireat key timestamp pexpireat key millinseconds-timestamp
-
获取key有效时间
ttl key # 查看key的剩余有效期 pttl key
-
持久化:切换key从时效性转换为永久性
persist key
-
-
对于key快速查询操作,例如:按指定策略查询key
-
查询key
keys pattern # 匹配模式 keys * # 查询所有 keys it* # 匹配以it开头的key keys ??hh # 一个问号匹配一个任意字符 keys n[aw]me # 中间字母是a和w中任意字符
-
-
key 其他操作
-
为key重命名
rename key newkey # 若newkey已经存在,那么会覆盖掉原来的值 renamenx key newkey # 如果newname已存在则失败,不存在才会改名
-
对所有 key 排序,不会修改原key的内容
sort key [desc # 逆序][...]
-
对其他 key 通用操作
help @generic
-
数据库通用操作
key重复问题:
- key是由程序员定义的
- redis在使用过程中,伴随着操作数据量的增加,会出现大量的数据以及对应的key
- 数据不区分种类,类别混杂在一起,极易出现重复或冲突
解决方案
-
redis为每个服务器提供有16个数据库,编号从0-15
-
每个数据库之间的数据互相独立【公用一个存储内存】
db 基本操作
-
切换数据库:
select index
(16个数据库) -
其他操作:
quit
ping
(测试cli是否和server保持连接)echo message
-
数据移动:
move key db
(类似于剪切操作,数据库之间移动数据) -
数据清除:
dbsize flushdb # 用这个也要小心 flushall # 这辈子都用不到,哈哈哈哈,删库跑路
1.4 Jedis
Java语言连接redis数据库的服务工具。
- 选定数据库
- 创建程序与数据库的连接
- 操作数据库
- 关闭连接
2 Redis 高级
2.1 Linux安装 redis
-
下载
wget http://download.redis.io/releases/redis-6.0.8.tar.gz
-
解压
tar xzf redis-6.0.8.tar.gz
-
进入目录
cd redis-6.0.8 make # 编译,生成redis-server和redis-cli
-
启动服务
cd src ./redis-server ../redis.conf # 默认配置启动服务端 ./redis-cli # 启动客户端
基本Linux命令
Linux变量基本都是字符串类型,双引号、单引号、不用引号都可,双引号中可以用变量、转义字符
my_url="http://www.baidu.com" # 变量命名规范(数字、字母、下划线),等号前后不能有空格
echo $my_url # 使用变量
your_name="spicy"
greeting="hello, ${your_name} ! Hello,"$your_name" !"
echo greeting
shell数组
array_name=(1 2 3 4 5)
${array_name[index]} # 读取
len=${#array_name[*]} # 数组长度,*可以换成@
多行注释:(EOF也可以换成其他符号)
:<<EOF
...
EOF
# 文件
ls -a # 显示指定工作目录下之内容
2.2 持久化
RDB:快照方式,将当前redis中所有的键值对保存到一个临时文件中,下次启动服务时自动恢复数据。
save # 每手动执行一次,就会保存一个临时文件
bgsave # 当多客户端访问时,save的数据较多,因为redis是单指令,可能会阻塞其他客户端访问redis,因此用这种方式后台判断执行顺序--->开启了新进程
save的conf配置 # 自动保存,通过更改save配置,save second changes
rdb特殊启动形式
- 全量复制,在主从复制中会提到
- 服务器运行过程中重启,debug reload
- 关闭服务器时指定保存数据
shutdown save
RDB优点
- RDB是一个紧凑压缩的二进制文件,存储效率较高
- RDB内部存储的是redis在某个时间点的数据快照,非常适合用于数据备份,全量复制等场景
- RDB恢复数据的速度要比AOF快很多
- 应用:服务器中每X小时执行bgsave备份,并将RDB文件拷贝到远程己气中,用于灾难恢复
RDB缺点
- RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具体较大的可能性丢失数据
- bgsave指令每次运行要执行fork操作创建子进程,要牺牲掉一些性能
- Redis的众多版本中未进行RDB文件格式的版本统一,有可能出现个版本服务之间数据格式无法兼容现象
RDB存储的弊端
- 存储数据量较大,效率较低——基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
- 大数据量下的IO性能较低
- 基于fork创建子进程(bgsave),内存产生额外消耗
- 宕机带来的数据丢失风险
解决思路
- 不写全数据,仅记录部分数据
- 改记录数据未记录操作过程
- 对所有操作均进行记录,排除丢失数据的风险
- 这也就是AOF的引入
AOF持久化
- 以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。与RDB相比可以简单描述为改记录数据产生的过程
- AOF的主要作用是解决了数据持久化的实时性,目前已经是Redis持久化的主流方式
AOF将数据操作先写到缓冲区,最后同步到.aof
文件。
AOF写数据的三种策略
- always(每次)
每次写入操作均同步到AOF文件中,数据零误差,性能较低【不建议使用】 - everysec(每秒)
每秒将缓冲区中的指令同步到AOF文件中,数据准确性高,性能较高
在系统突然当即的情况下丢失1秒内的数据 - no(系统控制)
由操作系统每次同步到AOF文件的周期,整体过程不可控
AOF重写
随着命令的不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入AOF重写机制压缩文件体积,AOF文件重写是将Redis进程内的数据转换为写命令同步到新AOF文件的过程,简单说就是将同样一个数据的若干个命令执行结果转换为最终结果数据对应的指令进行记录(如多条set name value
的操作,只需要保存最后一个命令即可;如多次插入lpush key value
,最后保存插入所有元素的语句即可)
AOF重写作用
- 降低磁盘占用量,提高磁盘利用路
- 提高持久化效率,降低持久化写时间,提高IO性能
- 降低数据恢复用时,提高数据恢复效率
AOF重写规则
- 进程内已超时的数据不再写入文件
- 忽略无效指令,重写时使用进程内数据直接生成,这样新的AOF文件只保留最终数据的写入命令 如del key1,hdel key2,srem key3,set key 222等
- 对统一数据的多条命令合并为一条命令
如 lpush list1 a ,lpush list1 b,lpush list1 c可以转化为lpush list1 a b c
为防止数据量过大造成客户端缓冲区溢出,对list,set,hash,set等类型,每条指令最多写入64个元素 - [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykIWXtuz-1619497596245)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20210427104306755.png)]
RDB 对比 AOF
如何选择RDB AOF?
- 对数据非常敏感,建议使用默认的AOF持久化方案
- AOF持久化策略使用everysecond,每秒钟fsync一次。该策略redis仍可以保持很好的处理性能,当出现问题时,最多丢失0-1秒内的数据。
- 注意:由于AOF文件存储体积较大,且恢复速度较慢
- 数据呈现阶段有效性,建议使用RDB持久化方案
- 数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案
- 注意:利用RDB实现紧凑的数据持久化会使Redis降的很低综合比对
- 综合比对
- RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
- 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
- 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
- 灾难恢复选用RDB
- 双保险策略,同时开启RDB和AOF,重启后,Redis优先使用AOF来恢复数据,降低丢失数据的量
持久化应用场景(有的应用需要存到DB中,就不必要放到redis中;一般临时的、热点的、快现快消的可以用redis存储,防止宕机快速重连)
2.3 事务
redis 事务是一个命令执行的队列,在执行的过程中,按照添加顺序依次执行,中间不会被打断或者被干扰
- 开启事务:
multi
- 结束事务:
exec
- 取消事务:
discard
事务工作流程:
锁:多用户同时访问某个key,要保障不会重复修改该key的value。
监视锁:watch key1 [key2 ...]
,一旦监控到的key发生改变(另外一个用户改变key),之后执行的事务都会失败,无论是否涉及到被监控的key。必须在开启事务之前监控。 取消锁unwatch
。在client A中对name进行监控,然后client B对name进行修改,那么client A的其他操作将不会被执行。如下所示,用了unwatch,取消监控,那么client B对name进行修改就不会影响client A了。
分布式锁
业务场景:当商品只有1件时,多个用户来抢购,如何加锁使得正常卖出商品?
设置公共锁,setnx lock-key value
del
删除锁
set num 10
setnx lock-num 1
业务场景:当加锁的用户宕机,导致锁无法解开,如何处理?(依赖分布式锁的机制,某个用户操作时对应客户机宕机,并且此时已经获取到锁,如何解决?)
使用expire
为key
添加时间限制,到时间不释放的话,就放弃该锁。
- 由于锁操作由用户控制加锁,必定会存在加锁后未解锁的风险
- 需要解锁操作不能仅依赖用户控制,系统级别要给出对应的保底处理方案
解决方案
-
使用expire为锁key添加时间限定,到时不释放,放弃锁
expire lock-key second pexpire lock-kay millisenconds
-
由于操作通常都是微秒或者毫秒级,因此该锁设定时间不宜设置过大。具体时间需要业务测试后确认
-
例如:持有锁的操作最长执行时间127ms,最短执行时间7ms
-
测试百万次最长执行时间对应命令的最大消耗时,测试百万次网络延迟平均耗时
-
锁时间设定推荐:最大耗时* 120%+平均网络延迟*110%
-
如果业务最大耗时<<网络平均延迟,通常为2个数量级,取其中单个耗时较长即可
2.4 删除策略
Redis中的数据特征
Redis是一种内存级数据库,所有数据均存放在内存中,内存中的数据可以通过TTL指令获取其状态
XX : 具有时效性的数据
-1 : 永久有效的数据
-2 : 已经过期的数据 或 被删除的数据 或 未定义的数据
数据删除策略
- 定时删除
- 惰性删除
- 定期删除
时效性数据的存储结构
地址、过期时间
根据过期时间删除,删除策略:在内存占用和CPU占用之间寻找一种平衡
2.5 redis.conf
2.5 集群
3 Redis 应用
企业级解决方案