一、redis简介
简单来说 redis 就是一个数据库,不过与传统数据库不同的是 redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向。另外,redis 也经常用来做分布式锁。
二、为什么要用 redis/为什么要用缓存?
主要从“高性能”和“高并发”这两点来看待这个问题。
高性能:
假如用户第一次访问数据库中的某些数据,这个过程会比较慢,因为是从硬盘上读取的。如果该用户访问的数据存在缓存中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。操作缓存是直接操作内存,所以速度相对硬盘要快很多。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!
高并发:
redis适合少写多读,符合缓存的适用要求。
官方数据表示Redis读的速度是十几万次/s,写的速度是八万次左右/s 。单机redis支撑万级,如果十万以上建议用redis replication模式,也就是集群模式;
三、redis 常见数据结构(5种)
1.String(字符串)
常用命令:set,get,decr,incr,mget 等。
String数据结构是简单的key-value类型,value其实不仅可以是String,也可以是数字。 常规key-value缓存应用:常规计数、定时器并发控制等。
2.Hash(哈希)
常用命令:hget,hset,hgetall 等。
hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象,后续操作的时候,你可以直接仅仅修改这个对象中的某个字段的值。 比如我们可以用 hash 数据结构来存储地址信息等。
3.List(列表)
常用命令: lpush,rpush,lpop,rpop,lrange等
list 就是链表,Redis list的应用场景非常多,比如消息队列就可以用Redis的 list 结构来实现。list 的实现为一个双向链表,即可以支持反向查找和遍历,方便操作,不过带来了部分额外的内存开销。
4.Set(集合)
常用命令: sadd,spop,smembers,sunion 等
set 对外提供的功能与list类似是一个列表的功能,特殊之处在于 set是可以自动排重的。当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。可以基于 set 轻易实现交集、并集、差集的操作。
比如:在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常方便的实现如共同关注、共同粉丝、共同喜好等功能。这个过程也就是求交集的过程,具体命令如下:
sinterstore key1 key2 key3 //将交集存在key1内
5.zset(有序集合)
常用命令: zadd,zrange,zrem,zcard等
zset 类似于 Java 的 SortedSet 和 HashMap 的结合体,一方面它是一个 set,保证了内部 value 的唯一性,另一方面它可以给每个 value 赋予一个 score,代表这个 value 的排序权重。举例:在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜等信息,适合使用 Redis 中的 Sorted Set 结构进行存储。
四、redis 设置过期时间(非特殊情况,redis都要设置过期时间!!!)
redis中有个设置时间过期的功能,即对存储在 redis 数据库中的值可以设置一个过期时间。作为一个缓存数据库,这是非常实用的。如我们一般项目中的 token 或者一些登录信息,尤其是短信验证码都是有时间限制的,按照传统的数据库处理方式,一般都是自己判断过期,这样无疑会严重影响项目性能。
我们 set key 的时候,都可以给一个 expire time,就是过期时间,通过过期时间我们可以指定这个 key 可以存活的时间。
现在假如我们设置了一个key的过期时间是五分钟,那么五分钟之后,redis是怎么对key进行删除的?(以下简单介绍,大家了解就好)
1.定期删除+惰性删除。
定期删除:redis默认是每隔 100ms 就随机抽取一些设置了过期时间的key,检查其是否过期,如果过期就删除。注意这里是随机抽取的。为什么要随机呢?你想一想假如 redis 存了几十万个 key ,每隔100ms就遍历所有的设置过期时间的 key 的话,就会给 CPU 带来很大的负载!
惰性删除:定期删除可能会导致很多过期 key 到了时间并没有被删除掉。所以就有了惰性删除。假如你的过期 key,靠定期删除没有被删除掉,还停留在内存里,除非你的系统去查一下那个 key,才会被redis给删除掉。这就是所谓的惰性删除,也是够懒的哈!
2.redis 内存淘汰机制
通过定期和惰性删除,还是有可能漏掉了很多过期 key(如果定期删除漏掉了很多过期 key,然后你也没及时去查,也就没走惰性删除),此时会怎么样?
后果:如果大量过期key堆积在内存里,导致redis内存块耗尽了。
怎么解决这个问题呢?
redis 提供 6种数据淘汰策略:
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。(这个个人不建议使用)
Redis4.0版本后增加以下两种:
volatile-lfu:从已设置过期时间的数据集(server.db[i].expires)中挑选最不经常使用的数据淘汰
allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的key
五、Redis常用命令
这里只列举本人在实际项目中常用到的redis命令,完整版可通过菜鸟教程相关章节了解。
完整命令网址:https://www.runoob.com/redis/redis-strings.html
1.String字符串命令
1.1 set/get
set key value
解释:设置指定 key 的值,将value关联到key。如果key已经持有其他值,则覆写旧值,无视类型。
get key
解释:获取指定 key 的值,如果key不存在则返回null
应用场景:方法a整合统计得到值,set缓存该值,方法b使用get获取的情况。
1.2 mGet
MGET key1 [key2..]
解释:获取所有(一个或多个)给定 key 的值,命令返回所有(一个或多个)给定 key 的值。 如果给定的 key 里面,有某个 key 不存在,那么这个 key 返回特殊值null
应用场景:一次性获取key为张三、李四、王五这三个对应的value值。
1.3 incr/decr
INCR key
解释:将key中储存的数字值加1,如果key不存在则自动创建并加1
应用场景:
1.统计每个设备被使用的次数,,每次累加1次。
2.定时器通过指定key对应的value值,判断方法是否执行过。
Decr key(将 key 中储存的数字值减1)
解释和应用场景,参考incr。
1.4 incrBy/decrBy
INCRBY key increment
解释:将 key 所储存的值加上给定的增量值increment,INCR key相当于INCRBY key 1
应用场景:统计每个设备被使用的次数,每次累加increment次。
DECRBY key decrement(key 所储存的值减去给定的减量值decrement)
解释和应用场景,参考incrBy
2. Hash哈希命令
2.1 Hdel
HDEL key field1 [field2](删除一个或多个哈希表字段)
2.2 Hexists
HEXISTS key field
解释:查看哈希表 key 中,指定的字段是否存在。返回0(不存在)或者1(存在)
应用场景:哈希表里缓存着存在用户今日实时的消费,定时器方法通过判断哈希是否存在决定是否更新该用户mysql里的消费总金额。
2.3 Hget
HGET key field
解释:通过整个哈希表的key和哈希表里的key(field)中指定字段的值
应用场景:哈希表里存放某天的用户id对应的使用设备次数,通过日期和用户id获取这个用户的使用设备次数
2.4 HgetAll
HGETALL key
解释:获取在哈希表中指定 key 的所有字段和值。
应用场景:定时器方法获取哈希表所有字段和值,统计整合存入数据库。
2.5 Hincrby
HINCRBY key field increment
解释:为哈希表 key 中的指定字段的整数值加上增量 increment
应用场景:因为小江表现优秀,老板决定给致上(哈希表key)的小江(指定字段),工资加10块钱以表奖励。
2.6 Hkeys
HKEYS key
解释:获取哈希表key下所有的key
应用场景:哈希表记录今日的用户消费情况,现在想知道今日有哪些用户消费了
2.7 Hlen
HLEN key
解释:获取哈希表key下key的数量
应用场景:哈希表记录今日的用户消费情况,现在想知道今日有多少用户消费了
2.8 Hmget
HMGET key field1 [field2]
解释:获取所有给定字段的值
应用场景:哈希表记录今日的用户消费情况,现在想拿到今日张三李四王五这三个人的消费情况
2.9 Hmset
HMSET key field1 value1 [field2 value2 ]
解释:同时将多个 field-value (域-值)对新增到哈希表 key 中
应用场景:新增几台设备,将设备的属性新增进缓存设备属性的哈希表里
2.10 Hset
HSET key field value
解释:将哈希表 key 中的字段 field 的值设为 value
应用场景:新增了一个设备,将设备的属性新增进缓存设备属性的哈希表里
2.11 hsetnx
HSETNX key field value
解释:用于为哈希表中不存在的的字段赋值
应用场景:哈希表记录今日的用户第一笔消费情况,当用户已存在哈希表里,不赋值。否则,赋值。
3. list列表命令
3.1 Lrange
LRANGE key start stop
解释:获取列表指定范围内的元素,不会移除元素
3.2 Llen
LLEN key
解释:获取列表的长度
应用场景:消息队列,获取队列list的长度,判断是否需要执行任务。如果长度为0,则表示无消息需要执行。
3.3 Lpop
LPOP key
解释:获取并移除list左边第一个元素
应用场景:消息队列,按顺序处理。获取当前第一个元素,执行任务。
3.4 lpush
LPUSH key value1 [value2]
解释:将一个或多个值 value 插入到list列表 key 的表头 如果有多个 value 值,那么各个 value 值按从左到右的顺序依次插入到表头:比如对一个空列表 mylist 执行 LPUSH mylist a b c ,则结果列表为 c b a ,等同于执行执行命令 LPUSH mylist a 、 LPUSH mylist b 、 LPUSH mylist c
应用场景:消息队列,按顺序处理。vip用户优先发送消息,直接不讲道理插入队列表头。
3.5 rpush
RPUSH key value1 [value2]
解释:将一个或多个值 value 插入到List列表 key 的表尾(最右边)
应用场景:消息队列,按顺序处理。将需要处理的元素插入最右边,排队等待处理
4. set集合命令
4.1 Sadd
SADD key member1 [member2]
解释:将一个或者多个值放到set中
应用场景:用户可多次使用设备,set存放使用过设备的用户(去重)
4.2 Sismember
SISMEMBER key member
解释:判断 member 元素是否是集合 key 的成员
应用场景:用户可多次使用设备,set存放使用过设备的用户,现在想知道某个用户有没有使用过
4.3 Srandmember
SRANDMEMBER key [count]
解释:随机返回set中的count个数据
应用场景:从有获奖资格的用户里,抽取count个幸运用户
4.4 scard
SCARD key
解释:获取key集合的成员数
应用场景:用户可多次使用设备,set存放使用过设备的用户,现在想知道有多少用户使用过
5. zset有序集合命令
5.1 Zadd
ZADD key score1 member1 [score2 member2]
解释:向有序集合添加一个或多个成员,或者更新已存在成员的分数
应用场景:抽奖活动,抽奖规则与参加顺序有关。添加多位参与者。
5.2 Zcard
ZCARD key
解释:获取有序集合的成员数
应用场景:抽奖活动,抽奖规则与参加顺序有关。现在想知道有多少参与者。
5.3 Zrange
ZRANGE key start stop [WITHSCORES]
通过索引区间返回有序集合指定区间内的成员