🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## redis的使用场景 (1)缓存 毫无疑问这是Redis当今最为人熟知的使用场景。再提升服务器性能方面非常有效; 一些频繁被访问的数据,经常被访问的数据如果放在关系型数据库,每次查询的开销都会很大,而放在redis中,因为redis 是放在内存中的可以很高效的访问。 (2)排行榜 在使用传统的关系型数据库(mysql oracle 等)来做这个事儿,非常的麻烦,而利用Redis的SortSet(有序集合)数据结构能够简单的搞定; (3)计算器/限速器 Redis中原子性的自增操作,我们可以统计类似用户点赞数、用户访问数等,这类操作如果用MySQL,频繁的读写会带来相当大的压力;限速器比较典型的使用场景是限制某个用户访问某个API的频率,常用的有抢购时,防止用户疯狂点击带来不必要的压力; (4)好友关系 利用集合的一些命令,比如求交集、并集、差集等。可以方便搞定一些共同好友、共同爱好之类的功能。 (5)简单消息队列 除了Redis自身的发布/订阅模式,我们也可以利用List来实现一个队列机制,比如:到货通知、邮件发送之类的需求,不需要高可靠,但是会带来非常大的DB压力,完全可以用List来完成异步解耦; (6)Session共享 以PHP为例,默认Session是保存在服务器的文件中,如果是集群服务,同一个用户过来可能落在不同机器上,这就会导致用户频繁登陆;采用Redis保存Session后,无论用户落在那台机器上都能够获取到对应的Session信息。 (7)分布式锁 分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。 链接地址:https://mp.weixin.qq.com/s/r9_0xpRsp2ubgyvpiyMfuw ## String ### 常规计数 ![](https://img.kancloud.cn/11/7c/117cc2b6e8fc42f3871907422c5319a0_855x549.png) ### 分布式锁 SET lock\_key unique\_value NX PX 10000 还是不安全 ## List ### 常用命令 ![](https://img.kancloud.cn/ca/c4/cac41e25332dbce5534749de6135c63d_832x501.png) ### 应用场景 #### 消息队列 List 可以使用 LPUSH + RPOP (或者反过来,RPUSH+LPOP)命令实现消息队列。 * 生产者使用`LPUSH key value[value...]`将消息插入到队列的头部,如果 key 不存在则会创建一个空的队列再插入消息。 * 消费者使用`RPOP key`依次读取队列的消息,先进先出。 建议使用BRPOP ,**BRPOP命令也称为阻塞式读取,客户端在没有读到队列数据时,自动阻塞,直到有新的数据写入队列,再开始读取新数据**。和消费者程序自己不停地调用RPOP命令相比,这种方式能节省CPU开销。 * 消息保序:使用 LPUSH + RPOP; * 阻塞读取:使用 BRPOP; * 重复消息处理:生产者自行实现全局唯一 ID;(eg:LPUSH mq "111000102:stock:99") * 消息的可靠性:使用 BRPOPLPUSH(读出来之后放到另一个list,作为备份) 缺点:不能多消费者,在redis5.0 之后增加了stream ,可以使用消费者组,进行消费 ## Hash ### 常用命令 ![](https://img.kancloud.cn/db/bc/dbbcb7a34fa6b7bc9aeba3feac2d4d93_423x586.png) ### 应用场景 #### 缓存对象 1、hset key feild value,可以单独取出key的某项信息去操作 ![](https://img.kancloud.cn/75/5d/755d45213970fc728c19b208323e6987_355x377.png) #### 购物车 ![](https://img.kancloud.cn/13/a8/13a8d647a07ebad6ade86197dac0a74a_1080x1202.png) 涉及的命令如下: * 添加商品:`HSET cart:{用户id} {商品id} 1` * 添加数量:`HINCRBY cart:{用户id} {商品id} 1` * 商品总数:`HLEN cart:{用户id}` * 删除商品:`HDEL cart:{用户id} {商品id}` * 获取购物车所有商品:`HGETALL cart:{用户id}` 当前仅仅是将商品ID存储到了Redis 中,在回显商品具体信息的时候,还需要拿着商品 id 查询一次数据库,获取完整的商品的信息。 ## Set ### 常用命令 Set常用操作: ![](https://img.kancloud.cn/f2/cb/f2cb3545be55c45a82a740a3b0644ae6_536x488.png) Set运算操作: ![](https://img.kancloud.cn/71/78/71785493ccbc169c327cc19ebabef2f8_406x437.png) ### 应用场景 集合的主要几个特性,无序、不可重复、支持并交差等操作。 **Set 的差集、并集和交集的计算复杂度较高,在数据量较大的情况下,如果直接执行这些计算,会导致 Redis 实例阻塞**。 #### 点赞 ``` //uid:1 用户对文章 article:1 点赞 SADD article:1 uid:1 //uid:1`取消了对 article:1 文章点赞。 SREM article:1 uid:1 //获取  article:1 文章所有点赞用户  SMEMBERS article:1 //获取 article:1 文章的点赞用户数量: SCARD article:1 //判断用户`uid:1`是否对文章 article:1 点赞了: SISMEMBER article:1 uid:1 ``` #### 关注 Set 类型支持交集运算,所以可以用来计算共同关注的好友、公众号等。 key 可以是用户id,value 则是已关注的公众号的id。 `uid:1`用户关注公众号 id 为 5、6、7、8、9,`uid:2` 用户关注公众号 id 为 7、8、9、10、11。 ![](https://img.kancloud.cn/83/9a/839a715c4f2ee9d97f3b288a577cd705_546x699.png) ![](https://img.kancloud.cn/6f/13/6f1368bbdb0e6230b780898638a97782_548x219.png) #### 抽奖 key为抽奖活动名,value为员工名称,把所有员工名称放入抽奖箱 : ~~~ SADD lucky Tom Jerry John Sean Marry Lindy Sary Mark ~~~ 如果允许重复中奖,可以使用 SRANDMEMBER 命令 ![](https://img.kancloud.cn/d9/ba/d9ba9ecce1b403dc81e9b4d22d94e6e8_355x376.png) 如果不允许重复中奖,可以使用 SPOP 命令。 ![](https://img.kancloud.cn/ff/c4/ffc4832e3a89cc617cbb12eba5eb0d1c_255x372.png) ## Zset ### 常用命令 Zset 常用操作: ![](https://img.kancloud.cn/00/87/0087bccff6cf2e1eea4d66a68fdad94d_575x725.png) Zset 运算操作(相比于 Set 类型,ZSet 类型没有支持差集运算): ![](https://img.kancloud.cn/be/21/be2144225752e9e2d43d51e248d48f9f_731x129.png) ### 应用场景 #### 排行榜 ![](https://img.kancloud.cn/3b/0f/3b0f0c93dc58861932b74eee2a76911a_817x564.png)![](https://img.kancloud.cn/69/29/6929278d2bfad2ef5d6e9f88cd334ad1_827x760.png) ![](https://img.kancloud.cn/e0/82/e0821b1a3ac3450c338cbc39fe69bfe5_818x324.png) #### 电话、姓名排序 使用有序集合的`ZRANGEBYLEX`或`ZREVRANGEBYLEX`可以帮助我们实现电话号码或姓名的排序,我们以`ZRANGEBYLEX`(返回指定成员区间内的成员,按 key 正序排列,分数必须相同)为例。 **注意:不要在分数不一致的 SortSet 集合中去使用 ZRANGEBYLEX和 ZREVRANGEBYLEX 指令,因为获取的结果会不准确。** ##### 电话排序 ![](https://img.kancloud.cn/ae/4f/ae4ff29502fc6c44b2b031194d123aa6_539x203.png) ![](https://img.kancloud.cn/bf/b6/bfb670fd98bb00513667fd074d11a6eb_323x582.png) ##### 姓名排序 ![](https://img.kancloud.cn/d6/7e/d67ee80ba2eb2bbad983ab3de874ec42_630x91.png) ![](https://img.kancloud.cn/76/a3/76a32a81ad30f4c4ee834d6c40129d62_375x708.png) ## Bitmap ### 简介 Bitmap,即位图,是一串连续的二进制数组(0和1),可以通过偏移量(offset)定位元素。BitMap通过最小的单位bit来进行`0|1`的设置,表示某个元素的值或者状态,时间复杂度为O(1)。 由于 bit 是计算机中最小的单位,使用它进行储存将非常节省空间,特别适合一些数据量大且使用**二值统计的场景**。 ![](https://img.kancloud.cn/9e/6a/9e6a9e501f1180b3901bad189fef20c1_1080x104.png) ### 内部实现 Bitmap 本身是用 String 类型作为底层数据结构实现的一种统计二值状态的数据类型。 String 类型是会保存为二进制的字节数组,所以,Redis 就把字节数组的每个 bit 位利用起来,用来表示一个元素的二值状态,你可以把 Bitmap 看作是一个 bit 数组。 ### 常用命令 bitmap 基本操作: ![](https://img.kancloud.cn/b8/dc/b8dc77dfe221f963a00c6aff3559f72c_366x298.png) bitmap 运算操作: ![](https://img.kancloud.cn/2a/93/2a932c19f5ee9f5a1f471ee4dd92c989_625x392.png) ### 应用场景 #### 签到统计 签到统计时,每个用户一天的签到用 1 个 bit 位就能表示,一个月(假设是 31 天)的签到情况用 31 个 bit 位就可以,而一年的签到也只需要用 365 个 bit 位,根本不用太复杂的集合类型。 ![](https://img.kancloud.cn/b8/8d/b88db7e88abd05850bd1f52ed41f1ad8_839x524.png) ![](https://img.kancloud.cn/ad/34/ad34361317f5046107688036a9e511ab_820x488.png) #### 判断用户登陆态 Bitmap 提供了`GETBIT、SETBIT`操作,通过一个偏移值 offset 对 bit 数组的 offset 位置的 bit 位进行读写操作,需要注意的是 offset 从 0 开始。 只需要一个 key = login\_status 表示存储用户登陆状态集合数据, 将用户 ID 作为 offset,在线就设置为 1,下线设置 0。通过`GETBIT`判断对应的用户是否在线。50000 万 用户只需要 6 MB 的空间。 ![](https://img.kancloud.cn/9d/20/9d20ed0142cba54a48260b82dbb93ec4_535x494.png) #### 连续签到用户总数 如何统计出这连续 7 天连续打卡用户总数呢? 我们把每天的日期作为 Bitmap 的 key,userId 作为 offset,若是打卡则将 offset 位置的 bit 设置成 1。 key 对应的集合的每个 bit 位的数据则是一个用户在该日期的打卡记录。 一共有 7 个这样的 Bitmap,如果我们能对这 7 个 Bitmap 的对应的 bit 位做 『与』运算。同样的 UserID offset 都是一样的,当一个 userID 在 7 个 Bitmap 对应对应的 offset 位置的 bit = 1 就说明该用户 7 天连续打卡。 结果保存到一个新 Bitmap 中,我们再通过`BITCOUNT`统计 bit = 1 的个数便得到了连续打卡 3 天的用户总数了。 Redis 提供了`BITOP operation destkey key [key ...]`这个指令用于对一个或者多个 key 的 Bitmap 进行位元操作。 * `opration`可以是`and`、`OR`、`NOT`、`XOR`。当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作`0`。空的`key`也被看作是包含`0`的字符串序列。 ![](https://img.kancloud.cn/30/a7/30a7f4d87525128f806a13ea09110bb5_779x392.png) ## HyperLogLog ### 简介 Redis HyperLogLog 是 Redis 2.8.9 版本新增的数据类型,是一种用于「统计基数」的数据集合类型,基数统计就是指统计一个集合中不重复的元素个数。但要注意,HyperLogLog 是统计规则是基于概率完成的,不是非常准确,标准误算率是 0.81%。 所以,简单来说 HyperLogLog**提供不精确的去重计数**。 HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的内存空间总是固定的、并且是很小的。 在 Redis 里面,**每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近`2^64`个不同元素的基数**,和元素越多就越耗费内存的 Set 和 Hash 类型相比,HyperLogLog 就非常节省空间。 ### 常用命令 ![](https://img.kancloud.cn/31/9f/319fb1efa3db1f6d47de2a7061463e15_436x274.png) ### 应用场景 #### 百万级网页 UV 计数 ![](https://img.kancloud.cn/34/e7/34e70ddff01808a9ff387ade1a22050f_831x350.png) HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。 这也就意味着,你使用 HyperLogLog 统计的 UV 是 100 万,但实际的 UV 可能是 101 万。虽然误差率不算大,但是,如果你需要精确统计结果的话,最好还是继续用 Set 或 Hash 类型。 ## Geo ### 简介 GEO 本身并没有设计新的底层数据结构,而是直接使用了 Sorted Set 集合类型。 GEO 类型使用 GeoHash 编码方法实现了经纬度到 Sorted Set 中元素权重分数的转换,这其中的两个关键机制就是「对二维地图做区间划分」和「对区间进行编码」。一组经纬度落在某个区间后,就用区间的编码值来表示,并把编码值作为 Sorted Set 元素的权重分数。 这样一来,我们就可以把经纬度保存到 Sorted Set 中,利用 Sorted Set 提供的“按权重进行有序范围查找”的特性,实现 LBS 服务中频繁使用的“搜索附近”的需求。 ### 常用命令 ``` # 存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。 GEOADD key longitude latitude member [longitude latitude member ...] # 从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。 GEOPOS key member [member ...] # 返回两个给定位置之间的距离。 GEODIST key member1 member2 [m|km|ft|mi] # 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。 GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] ``` ### 应用场景 ![](https://img.kancloud.cn/fc/8a/fc8ae0bdb1ec3fa369a7121adb255b7b_822x682.png)