1、Redis常见的数据结构
- 5种基础的:字符串(String)、列表(List)、集合(Set)、哈希(Hash)、有序集合(Zset)
- 3种特殊的:基数统计(HyperLogLogs)、位存储(Bitmap)、地理位置(Geospatial)
String
- String是Redis最基本的类型。
- String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如字符串、整数、jpg图片或者序列化的对象。
- 一个Redis中字符串最多可以是512M。
- 使用场景:
- 常规数据(比如 session、token、序列化后的对象、图片的路径)的缓存。
- 常规计数:微博数,粉丝数,用户单位时间的请求数。
- 分布式锁(利用
SETNX key value命令可以实现一个最简易的分布式锁)。 - 共享 session 信息
List
- 单键多值,是一个有序可重复的集合
- Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
- 它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。因此支持正向、反向双重查找。
- 使用场景:
- 信息流展示:最新回复、最新动态
- 用作缓存
- 消息队列:生产者可以将消息添加到List的头部,而消费者可以从List的尾部获取并处理消息(但是有两个问题:1. 生产者需要自行实现全局唯一 ID;2. 不能以消费组形式消费数据)
Set
- Redis的Set是一种无序集合。它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。
- 此外还提供了交集、并集、差集等一系列直接操作集合的方法。
- 应用场景:
- 网站UV统计(数据量巨大的场景还是
HyperLogLog更适合一些)、文章点赞、动态点赞 - 需要获取多个数据源交集、并集、差集的场景:共同好友、共同粉丝、共同关注、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集)
- 需要随机获取数据源中的元素场景:抽奖系统、随机点名
- 网站UV统计(数据量巨大的场景还是
Hash
- 是一个键值对集合。
- 是一个string类型的field和value的映射表,特别适合用于存储对象。类似Java里面的Map<String,Object>,并且可以像数据库中update一个属性一样只修改某一项属性值。
- 应用场景:
- 对象数据存储场景:用户信息、商品信息、购物车信息
Zset
- 与set 相似,不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了。
- 因为元素是有序的,所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。
- 访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
- 使用场景:
- 根据某个权重进行排序的场景:各种排行榜(直播间送礼物排行榜、微信运动步数排行榜、话题热度排行榜)
- 有优先级或者重要程度的场景:优先级任务队列等
三种特殊数据类型:
- Geospatial(GEO):Redis在3.2推出Geo类型,该功能可以推算出地理位置信息,两地之间的距离,比如滴滴打车。
- HyperLogLog:基数:数学上集合的元素个数,是不能重复的。这个数据结构常用于统计网站的 UV。
- Bitmap:bitmap就是通过最小的单位bit来进行0或者1的设置,表示某个元素对应的值或者状态。一个 bit 的值,或者是0,或者是1;也就是说一个 bit 能存储的最多信息是2。bitmap常用于二值状态统计的场景,比如签到、判断用户登陆状态、连续签到用户总数、统计用户信息(如活跃粉丝和不活跃粉丝)等;
2、String还是Hash存储对象数据更好?
- String 存储的是序列化后的对象数据,存放的是整个对象。Hash 是对对象的每个字段单独存储,可以获取部分字段的信息,也可以修改或者添加部分字段,节省网络流量。如果对象中某些字段需要经常变动或者经常需要单独查询对象中的个别字段信息,Hash 就非常适合。
- String 存储相对来说更加节省内存,缓存相同数量的对象数据,String 消耗的内存约是 Hash 的一半。并且,存储具有多层嵌套的对象时也方便很多。如果系统对性能和资源消耗非常敏感的话,String 就非常适合。
在绝大部分情况,我们建议使用 String 来存储对象数据即可!
3、使用Bitmap统计活跃用户怎么做?
Bitmap是一种用于存储大量数据的数据结构,它可以快速检索数据,并且可以在极少的内存中运行。它的实现原理是,将数据集中的每个元素映射到一个位图中,然后根据需要检索数据。
Bitmap 存储的是连续的二进制数字(0 和 1),通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。
你可以将 Bitmap 看作是一个存储二进制数字(0 和 1)的数组,数组中每个元素的下标叫做 offset(偏移量)。
如果想要使用 Bitmap 统计活跃用户的话,可以使用日期(精确到天)作为 key,然后用户 ID 为 offset,如果当日活跃过就设置为 1。
初始化数据:
SETBIT 20210308 1 1
(integer) 0
SETBIT 20210308 2 1
(integer) 0
SETBIT 20210309 1 1
(integer) 0
统计 20210308~20210309 总活跃用户数:
BITOP and desk1 20210308 20210309
(integer) 1
BITCOUNT desk1
(integer) 1
统计 20210308~20210309 在线活跃用户数:
BITOP or desk2 20210308 20210309
(integer) 1
BITCOUNT desk2
(integer) 2
4、使用 HyperLogLog 统计页面 UV 怎么做?
HyperLogLog是一种用于估算大型数据集中不同元素的数量的算法,它可以在极少的内存中运行,而不需要存储所有元素。它的实现原理是,将数据集中的每个元素哈希到一个小的数字空间中,然后计算每个哈希值的最高位,最后将这些最高位的最大值作为估算值。
使用 HyperLogLog 统计页面 UV 主要需要用到下面这两个命令:
PFADD key element1 element2 ...:添加一个或多个元素到 HyperLogLog 中。PFCOUNT key1 key2:获取一个或者多个 HyperLogLog 的唯一计数。
1、将访问指定页面的每个用户 ID 添加到 HyperLogLog 中。
PFADD PAGE_1:UV USER1 USER2 ...... USERn
2、统计指定页面的 UV。
PFCOUNT PAGE_1:UV