redis学习(概述、命令、雪崩等的理解篇)
概述
Redis(Remote Dictionary Server ),即远程字典服务,是⼀个开源的使⽤ ANSI C 语⾔编写、⽀持⽹络、可基于 内存亦可持久化的⽇志型、Key-Value数据库,并提供多种语⾔的 API。
redis ⾃身是⼀个 Map ,其中所有的数据都是采⽤ 有具体类型的数据。 key : value 的形式存储 key 是⼀个字符串, value 是具 Redis 中包含5种基本数据类型和3种特殊类型。
命令
基本命令
#1.切换数据库 select index #2.清屏命令 clear # 3.获得当前库中的key # "*"匹配任意数量的任意字符 "?"匹配任意⼀个字符 "[]"匹配其中的任意⼀个字符 keys pattern keys * (获得所有的key) keys d* (获得所有以d开头的key) keys *blue (获得所有以blue结尾的key) keys ?ava (获得前⾯有⼀个任意字符,并且以ava结尾的key) keys u[se]r (获得前⾯第⼀个字符是u,第⼆个字符是s或e,结尾为r的key) # 4.判断key是否存在 exists key # 5.判断key是什么类型 type key # 6.删除指定的key del key # 7.设置key的过期时间 expire key 1 (秒为单位) pexpire key 1 (毫秒为单位) # 8.查看过期剩余时间(-1表示永不过期,-2表示已过期) ttl key # 9.将key的有效期设置为永不过期 persist key # 10.修改key的名字 rename key newkey #如果newkey存在则会替换原来的value rename str str1 #将str的key改名为str1 renamenx str str1 #将str的key改名为str1,如果str1不存在才修改,如果存在则修改失败 # 11.对key中的数据进⾏排序,只针对集合类型(list,set) sort key sort list [asc|desc] #对key为list的集合进⾏排序(注意不改变原始数据) # 12.查看库中key的数量 dbsize # 13.清楚当前库的所有key flushdb #14.清除所有库中的数据(经常用) flushall # 15.退出命令 quit exit ESC键 # 16.检测客户端与服务器连通命令 ping # 17.控制台打印命令 echo message # 18.数据在不同的库中移动 move key db move name 1 #将当前库中的name数据移动到1号库中(注意:当前库中存在name数据,1号库中不存在同名的数据) # 19.获得当前Redis的运⾏属性值 info
字符串相关命令(重)
String 是 Redis 中最基本的类型, String 类型是⼆进制安全的,redis 的 string 可以存储任何数据,如图 片、对象等。
# 存值命令 set key value # 存放单个元素 mset key1 value1 key2 value2 key3 value3 ... # 批量存放 # 取值命令 获取数据时返回值为nil表示空,没有获取数据 get key # 获取单个元素 mget key1 key2 key3 ... # 批量获取多个元素 # 获得字符串的⻓度 strlen key # 向value中追加数据(如果原始数据存在就追加,否则新建) append key value # 截取字符串 endIndex:-1代表⾃然结束 getrange key startIndex endIndex # 替换内容 setrange key startIndex 替换内容 # 如果存在就不设置,不存在就新建 setnx key value #如果存在什么都不做,如果不存在就新建⼀个数据 # 数值运算指令 # 加法操作 incr key #对key的值⾃加1,等同于i++ incrby key number #对key的值加上指定的数值(负值进⾏减法运算),等同于i=i+n # 减法运算 decr key #对key的值⾃减1,等同于i-- decr by key number #对可以的值减去指定的数值 # 设置带有时效的数据 # 以秒为单位设置存活时间 setex key seconds value # 以毫秒为单位设置存活时间 psetex key milliseconds value # 使⽤set⽅式设置key的存活期 set key value [ex seconds][px milliseconds]
Hash 相关命令(重)
# 添加/修改数据 hset key field value # 获取数据 hget key field # 删除数据 hdel key field # 添加/修改多个数据 hmset key field1 value1 field2 value2 ... # 获取多个数据 hmget key field1 field2 ... # 获取hash中的字段数量 hlen key # 获取hash中是否包含指定字段 hexists key field # 获取hash中的所有字段名和字段值 hkeys key #获得所有的字段名 hvals key #获得所有字段值 # 设置指定字段的数值增加或减少 hincrby key field number #增加或减少整数(负数为减少) hincrbyfloat key field number #增加或减少⼩数(负数为减少)
List 相关命令(重)
# 向列表中添加数据(左部添加/右部添加) lpush key value #向队列的头部插⼊元素(左) lpush list aaa #向队列的头部插⼊⼀个元素 lpush list aaa bbb ccc #向队列中插⼊多个元素 rpush key value #向队列的尾部插⼊元素(右) rpush list aaa #向队列的尾部插⼊⼀个元素 rpush list aaa bbb ccc #向队列中插⼊多个元素 # 从list中获取元素 lrange key startIndex endIndex #根据起始和结束下标获取此范围内的列表元素 lrange list 0 1 #结果 aaa,bbb lrange list 0 -1 #将list中的所有元素取出 # 从list中弹出元素 lpop key #获得列表头部的第⼀个元素并从列表中移除 lpush list aaa bbb ccc ddd lpop key #获取并移除元素"ddd" rpop key #获得列表尾部的第⼀个元素并从列表中移除 rpop key #获取并移除元素aaa # 通过下标获取list中的某个元素 lindex key index # 获得列表中元素的数量(⻓度) llen key # 根据元素值从列表中移除指定数量的元素 lrem key count value lrem list 2 aaa #将list中的aaa元素移除,存在两个移除两个(最多移除两个) # 截取⼦list(截断⼦元素) ltrim key start end lpush list aaa bbb ccc ddd eee ltrim list 0 3 结果:eee ddd ccc bbb # 将原列表中最后⼀个元素移到新列表中 rpoplpush oldkey newkey lpush list aaa bbb ccc ddd eee rpoplpush list newlist #将list中的最后⼀个元素移动到newlist中 lrange list #结果 bbb ccc ddd eee lrange newlist #结果 aaa # 根据下标重置list中的⼀个元素(根据下标修改list中的⼀个元素) lset key index value # 向某个元素前或后插⼊⼀个元素 linsert list before|after oldvalue insertvalue
Set 相关命令
# 向set集合添加⼀个元素 sadd key value1 value2 .... # 查看set集合中的所有元素 smembers key # 判断⼀个元素是否存在于set集合中(0表示不存在 1表示存在) sismember key value # 获取set中元素的个数 scard key # 移除⼀个元素 srem key value # 随机抽取⼀个元素 srandmember key [count] #随机抽取⼀个或多个元素 # 随机删除元素 spop key [count] #随机删除⼀个或多个元素 # 将⼀个特定的值,移动到另⼀个set集合中 smove oldkey newkey value # 集合操作 # 1. 差集 sdiff key1 key2 # 2. 交集 sinter key1 key2 # 3. 并集 sunion key1 key2
ZSet 相关命令
该集合是对 set 集合的改造,在 set 集合中加⼊了⼀个字段值,⽤于存储排序规则数据,该数据只负责排序不起 其他作⽤。
# 向zset集合添加元素 zadd key score1 value1 score2 value2 #向zset集合添加⼀个或多个成员 # 获取zset中的元素 # 1.zrange key start end [withscores] #从⼩到⼤的顺序显示元素信息,withscores显示排序规则字段 # 2.zrevrange key start end [withscores] #从⼤到⼩的顺序显示元素信息,withscores显示排序规则字段 # 按条件获取zset中的元素 # 1.zrangebyscore key min max [limit] [withscores] zrangebyscore salary 9000 12000 limit 0 2 withscores #查询⼯资在9000到12000之间的员⼯名并显示前 两个 # 2.zrevrangebyscore key max min [limit] [withscores] #降序 zrevrangebyscore salary 13000 10000 limit 0 2 withscores #查询⼯资在12000到90000之间的员⼯名并 显示前两个 # 增加或减少zset中元素的score值 zincrby key increment value zincrby topn 200 java #把key为topn的的java属性的score添加200 # 删除zset中的元素 zrem key member1 member2 ... #根据元素名删除⼀个或多个元素 zrem salary xiaoming xiaoqiang zremrangebyrank key start stop #删除下标指定范围的元素 zremrangebyrank salary 0 2 zremrangebyscore salary min max #根据socres指定范围删除元素 zremrangebyscore salary 9000 12000 # 获取指定值的分数 zscore key value # 获得元素在集合中的排名 zrank key member # 升序排名 zrank topn java #排名从0开始,根据score升序排序 zrevrank key member # 降序排名 zrevrank topn java #排名从0开始,根据score降序排序 # 获得集合中元素数量 # 1.zcard key #获得集合中元素数量 zcard salary # 2.zcount key min max #获得指定范围的元素数量 zcount salary 9000 12000 # 集合交集和并集 #1.zinterstore newset setcount set1 set2 ...#集合交集操作,将多个集合的交集存⼊到newset集合中,相 交集合的数量个setcount指定的数量要⼀致,默认对交集数据进⾏求和运算,也可以获得最⼤值或最⼩值等运算 zinterstore ss 2 s1 s2 [aggregate max|min] #2.zunionstore newset setcount set1 set2 ...#集合并集操作 zunionstore ss 2 s1 s2 [aggregate max|min]
使用redis的原因
随着移动互联⽹的快速发展,互联⽹的⽤户数量越来越多,产⽣的数据规模也越来越⼤,对数据库也提出了更⾼的 要求,为了减少直接访问数据库,我们会⽤ Redis 作为缓存层。 因为 Redis 是内存数据库,我们可以将数据库的数据缓存在 Redis ⾥,相当于数据缓存在内存,内存的读写速 度⽐硬盘快好⼏个数量级,这样⼤⼤提⾼了系统性能。
雪崩、击穿、穿透的理解

缓存雪崩
通常我们为了保证缓存中的数据与数据库中的数据⼀致性,会给 Redis ⾥的数据设置过期时间,当缓存数据过期 后,⽤户访问的数据如果不在缓存⾥,业务系统需要重新⽣成缓存,因此就会访问数据库,并将数据更新到 Redis ⾥,这样后续请求都可以直接命中缓存。
当大量数据在同一时间过期时或者 Redis 故障宕机时,这时⼤量的⽤户请求,因为redis中数据过期了,所以就直接访问到数 据库了,从⽽导致数据库的压⼒骤增,严重的会造成数据库宕机,从⽽造成整个系统崩溃,这就是造成缓存雪崩的 原因。
雪崩的主要原因:
1.⼤量数据同时过期。
2.Redis 故障宕机。
解决方法:
针对大量数据过期的解决办法:
1.均匀设置过期时间
如果要给缓存数据设置过期时间,应该避免将⼤量的数据设置成同⼀个过期时间。我们可以在对缓存数据设置过期 时间时,给这些数据的过期时间加上⼀个随机数,这样就保证数据不会在同⼀时间过期。
2.互斥锁
当业务线程在处理⽤户请求时,如果发现访问的数据不在 Redis ⾥,就加个互斥锁,保证同⼀时间内只有⼀个请 求来构建缓存,当缓存构建完成后,再释放锁。未能获取互斥锁的请求,要么等待锁释放后重新读取缓存,要么就 返回空值或者默认值。
3.双 key 策略
我们对缓存数据可以使⽤两个 key ,⼀个是主 key 不⼀样,但是 key ,会设置过期时间,⼀个是备 key ,不会设置过期,它们只是 value 值是⼀样的,相当于给缓存数据做了个副本。
4.后台更新缓存
业务线程不再负责更新缓存,缓存也不设置有效期,⽽是让缓存“永久有效”,并将更新缓存的⼯作交给后台线程定 时更新。
Redis 故障宕机解决办法:
1.服务熔断或请求限流机制
因为 Redis 故障宕机⽽导致缓存雪崩问题时,我们可以启动服务熔断机制,暂停业务应⽤对缓存服务的访问,直接 返回错误,不⽤再继续访问数据库,从⽽降低对数据库的访问压⼒,保证数据库系统的正常运⾏,然后等到 Redis 恢复正常后,再允许业务访问缓存服务。
服务熔断机制是保护数据库的正常允许,但是暂停了业务应⽤访问缓存系统,全部业务都⽆法正常⼯作。
2.构建 Redis 缓存⾼可靠集群
服务熔断或请求限流机制是缓存雪崩发⽣后的应对⽅案,我们最好通过主从节点的⽅式构建 集群。 Redis 缓存⾼可靠集群。如果 Redis 缓存的主节点故障宕机,从节点可以切换成主节点,继续提供缓存服务,避免了由于 Redis 故障宕 机⽽导致缓存雪崩问题。
缓存击穿
我们的业务通常会有⼏个数据会被频繁地访问,⽐如秒杀活动,这类被频繁地访问的数据被称为热点数据。 如果缓存中的某个热点数据过期了,此次⼤量的请求访问了该热点数据,就⽆法从缓存中读取,直接访问数据库, 数据库很容易就被⾼并发的请求冲垮,这就是缓存击穿的问题。
原因流程:
1.大量的读请求
2.请求中的部分热点数据过期,导致缓存失败
3.因为访问redis没有得到数据,所以转为大量的请求去直接访问数据库
通俗例子:
双⼗⼀小马突发奇想,想拍卖一双有科比签名的篮球鞋,程序员将该鞋的信息存到了 redis 中,设置了3⼩时过期。寻思3⼩时够他们抢了吧,但他低估了科比的魅⼒。 该商品引起了⼀千万⼈关注,这些⼈不断的竞拍这双鞋,价格越拍越⾼,小马乐开了花。 竞拍了2⼩时59分,⻢上要拍到⼀个亿了,突然这双鞋在 redis ⾥的 key 数据过期了,导致该 key 的⼤量请 求,都打到了数据库,直接导致数据库挂掉了,服务⽆法响应。
意思就是非常多的请求正在访问一个数据,然后这个数据突然过期,那么直接全部去访问数据库,然后导致击穿。
解决办法:
1.互斥锁⽅案
保证同⼀时间只有⼀个业务线程更新缓存,未能获取互斥锁的请求,要么等待锁释放后重新读取 缓存,要么就返回空值或者默认值。
2.不给热点数据设置过期时间
由后台异步更新缓存,或者在热点数据准备要过期前,提前通知后台线程更新缓 存以及重新设置过期时间。
缓存穿透
当发⽣缓存雪崩或击穿时,数据库中还是保存了应⽤要访问的数据,⼀旦缓存恢复相对应的数据,就可以减轻数据 库的压⼒,⽽缓存穿透就不⼀样了。
当⽤户访问的数据,既不在缓存中,也不在数据库中,导致请求访问缓存时,发现缓存缺失,再去访问数据库时, 发现数据库中也没有要访问的数据,⽆法构建缓存数据来服务后续的请求。那么当有⼤量这样的请求到来时,数据 库的压⼒骤增,这就是缓存穿透的问题。
原因流程:
大量的请求访问redis,然后这些请求redis中没有,然后去访问数据库,数据库也没有,无法备份到redis中,然后就一直访问数据库,导致穿透。
缓存穿透发⽣的情况
缓存穿透的发⽣⼀般有这两种情况:
1.业务误操作,缓存中的数据和数据库中的数据都被误删除了,所以导致缓存和数据库中都没有数据。
2.⿊客恶意攻击,故意⼤量访问某些读取不存在数据的业务。
解决方法:
1.⾮法请求的限制。
判断请求参数是否合理,请求参数是否含有⾮法值、请求字段是否存在,如果判断出是恶意请求就直接返回错误,避免进⼀步访问缓存 和数据库。
2.缓存空值或者默认值。
当我们线上业务发现缓存穿透的现象时,可以针对查询的数据,在缓存中设置⼀个空值或者默认值,这样后续请求 就可以从缓存中读取到空值或者默认值,返回给应⽤,⽽不会继续查询数据库。
3.使⽤布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。
使⽤布隆过滤器快速判断数据是否存在,避免通过查询数据库来判断数据是否存在。我们可以在写⼊数据库数据 时,使⽤布隆过滤器做个标记,然后在⽤户请求到来时,业务线程确认缓存失效后,可以通过查询布隆过滤器快速 判断数据是否存在,如果不存在,就不⽤通过查询数据库来判断数据是否存在。
即使发⽣了缓存穿透,⼤量请求只会查询 Redis 和布隆过滤器,⽽不会查询数据库,保证了数据库能正常运⾏, Redis ⾃身也是⽀持布隆过滤器的。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)