【Redis从入门到放弃系列 四】数据结构应用场景

距离上一次对redis的学习【Redis从入门到放弃系列 三】数据结构居然已经过去一年多了,还是自己没有坚持下去吧,今年刚好在学中间件,那么还是继续顺着学下去吧,但是总要复习一下并且更好的总结提升,那么本篇blog在既往的三篇之上做好总结并且有更深入的探索,方便后续的学习。按照如下的目录去组织:

  • Redis的基本概念与特点:Redis的基本概念是什么,有什么特点
  • Redis的安装与使用:windows版本的服务端与客户端的安装
  • Redis的应用场景:总体的应用场景有哪些,为什么有Reids的需求
  • Redis的数据结构及对应场景:分类的数据结构及每一类的结构具体应用场景有哪些

那么从这四方面的角度出发来重新认识下Reids。

Redis的基本概念与特点

Redis通俗的说就是一种远程数据字典服务,用C语言开发的,那必须快,redis在现在的应用中使用的非常广泛。它的典型应用是:内容缓存,主要用于处理大量数据的高访问负载,优点就是快速查询
【Redis从入门到放弃系列 四】数据结构应用场景
在整个系统架构中其实一般用于热点信息或者高频信息的获取等。

Redis的安装与使用

简单的功能可以在Windows上安装一个,进行基本命令的操作,可以直接从我的网盘下载win-redis-64,提取码为redi,下载直接解压后可以看到Redis的目录非常简单,只有以下六个文件:
【Redis从入门到放弃系列 四】数据结构应用场景
而我们实际常用的文件只有两个,一个客户端一个服务端,启动服务端后,就可以在客户端进行任意的操作,服务端界面如下:
【Redis从入门到放弃系列 四】数据结构应用场景
一个服务端绑定一个端口,如果需要在一台机器上开启多个,需要复制几个实例,并且设置不同的端口号。而PID就是实例ID,每次启动都是一个随机值。客户端如下:
【Redis从入门到放弃系列 四】数据结构应用场景
相当于一个命令窗口,使用命令进行Redis操作即可。

Redis的应用场景

实际上在【Redis从入门到放弃系列 二】基本概念这篇blog中已经详细论证过为什么需要使用NoSql
数据库以及它要解决的Web2.0时代的问题,在整个分布式技术系列文章中我也反复说明了,其实分布式的解决方案其实就是为了解决海量增长的业务数据的性能瓶颈问题:高并发读写、海量数据的高效率存储和访问、高可拓展性和高可用性,我之前整理的Kafka、ElasticSearch以及Cassandra都需要满足以上三个功能特性,然后作为服务的一部分被架构到系统中,所以Redis被设计出来也是为了对这类问题处理的补充,那么当然它也应该具备这些特性。
【Redis从入门到放弃系列 四】数据结构应用场景
在一个经典的场景中各类中间件都承担一部分的职责,当然每一种职责都有其替代品。现在我司目前的这一套内容是【Cassandra(业务数据)+ElasticSearch(全文检索)+SqlServer\MySql(数据存储)+Redis(数据缓存)+Kafka(消息中间件)】,我相信任何公司使用的时候应该也是大同小异。但Redis的应用场景也不只是热点信息的存储,常用到的应用场景如下:

  • 缓存,缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。存储访问频率高的热数据防止穿透到数据库。
  • 排行榜,很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。sorted_set数据结构
  • 计数器,什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。
  • 分布式会话,集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心的session服务,session不再由容器管理,而是由session服务及内存数据库管理。
  • 分布式锁,在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。
  • 社交网络,点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。hash、list数据结构
  • 最新列表,Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID去到对应的内容页即可。list数据结构
  • 消息队列,消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。list数据结构

接下来我们在对应的数据结构中一一探讨哪种数据结构适合哪种场景。

Redis的数据结构及对应场景

我们说Redis有五种常用的数据结构,在【Redis从入门到放弃系列 三】数据结构中也对每种数据结构的操作进行过介绍,那么本篇blog其实更侧重对于每种数据结构的应用场景的讨论。
【Redis从入门到放弃系列 四】数据结构应用场景
需要注意的一点就是,Redis本身就是个Map,预置明确这个前提后,我感觉后续的讨论中才不会感觉凌乱。接下来每一部分都分为:基本操作、扩展操作【应用场景】、操作规范

String类型

string类型存储的其实就是一个字符串,需要注意的是如果字符串以整数的形式展示,可以作为数字操作使用,也就是我们说的自增操作。
【Redis从入门到放弃系列 四】数据结构应用场景

基本操作

了解下基本命令和单指令多指令操作的区别。

基本命令

也就是一次就处理一个key,对key进行增(改)、删、查
【Redis从入门到放弃系列 四】数据结构应用场景
需要注意的是,操作状态返回的0和1要和返回结果做区分,并且set操作其实是【有则更新,无则新增】
【Redis从入门到放弃系列 四】数据结构应用场景
当然还有多指令操作-顾名思义就是一次操作多个key和简单的获取及追加操作
【Redis从入门到放弃系列 四】数据结构应用场景

单指令与多指令操作

基本的操作功能点分为单指令操作多指令操作,也就是一次操作一个key或者一次操作多个key,什么情况下使用哪种指令模式需要注意:多指令效率高一些,但是有阻塞的风险,一条指令承载太多了
【Redis从入门到放弃系列 四】数据结构应用场景

扩展操作【应用场景】

这里string一般有如下三个应用场景,其实说白了string类型做的操作都是最基本的操作。

  • 场景一:利用数值操作特性为分布式数据库主键自增
  • 场景二:利用key的生命周期做投票系统
  • 场景三:利用string特性做热点数据刷新

当我们简单场景使用时,尤其是有些数值类型操作时,string是不二之选。

场景一:利用数值操作特性为分布式数据库主键自增

redis的string结构可以解决分布式数据库中的主键唯一性问题:
【Redis从入门到放弃系列 四】数据结构应用场景
使用incr命令即可做到,在队列自增然后分发到各个数据库中
【Redis从入门到放弃系列 四】数据结构应用场景
而且redis是单线程的,所以不存在并发问题
【Redis从入门到放弃系列 四】数据结构应用场景

场景二:利用key的生命周期做投票系统

在投票的场景中,我们经常会有一天可投几次票这样的限制,那么这个就需要一个过期时间,当然其实也可以作为锁的过期时间来使用
【Redis从入门到放弃系列 四】数据结构应用场景

使用setex来设置过期时间。
【Redis从入门到放弃系列 四】数据结构应用场景

场景三:利用string特性做热点数据刷新

可以把大V的各种属性【粉丝数、blog数以及关注数】等设置为一个string类型的key,value为数量,直接简单增加或减少操作即可。
【Redis从入门到放弃系列 四】数据结构应用场景

操作规范

一般数据库的热点数据设置格式如下:
【Redis从入门到放弃系列 四】数据结构应用场景

只有每隔一个时间才把这些数据持久化,大大减少IO交互及性能的损耗。

Hash类型

其实在string类型中我们知道,string的字符串也可以是一个map格式的,但是map格式里的数据处理就需要编程进行了,基于我们实际场景中遇到的多为对象,我们对对象的更新操作必不可少,hash类型也就很有必要。
【Redis从入门到放弃系列 四】数据结构应用场景

当然其底层存储数据结构为哈希表。
【Redis从入门到放弃系列 四】数据结构应用场景

基本操作

hash的基本操作和string其实类似,只不过在值的指定和设置时多加了一个维度,也就是字段。
【Redis从入门到放弃系列 四】数据结构应用场景
当然其也具备类多指令操作,一次修改多个字段值
【Redis从入门到放弃系列 四】数据结构应用场景

扩展操作【应用场景】

hash的主要特性是对象存储模式,我们看基于这样的特性,常用的有哪些场景呢?

  • 场景四:利用hash的对象存储特性设置用户的购物车
  • 场景五:hash作为商品秒杀计数对象完成商品秒杀系统

这两个业务场景其实在我们生活中还是很常见到的。可以把hash理解为一个复合的string

场景四:利用hash的对象存储特性设置用户的购物车

一个人的购物车可以看做一个对象,而商品可以当做field,数量可以当做value。然后对购物车进行各种操作,hash基本都能满足:
【Redis从入门到放弃系列 四】数据结构应用场景
例如对于一些操作场景:
【Redis从入门到放弃系列 四】数据结构应用场景

除了基本操作,我们想要增加商品数量,全选查看等都可以使用如下操作:
【Redis从入门到放弃系列 四】数据结构应用场景
当然我们当前只能拿到商品数量和商品,对于商品的详细信息一无所知,这个时候就需要对field做更细粒度的拆分:
【Redis从入门到放弃系列 四】数据结构应用场景

此时我们又想到,其实商品的信息是公共的,可以将公共的商品信息维护一个商品的hash,可以避免不同的人重复放置购物车占据大量内存,还是只存商品的编号和数值,需要的时候从公共hash取商品详细信息,同时为了避免重复商品入商品hash,使用setnx实现,这样实现性能最优。
【Redis从入门到放弃系列 四】数据结构应用场景

场景五:hash作为商品秒杀计数对象完成商品秒杀系统

【Redis从入门到放弃系列 四】数据结构应用场景
可以利用hash多字段的特性,来用一个对象完成整体秒杀系统。
【Redis从入门到放弃系列 四】数据结构应用场景

操作规范

hash操作有如下的使用规范,最主要的就是别无限套娃,禁止套娃!
【Redis从入门到放弃系列 四】数据结构应用场景
同时我们知道string也能存类hash的字符串,但是不能对其中字段操作,但是查看起来是一个完整格式,所以我们总结:
【Redis从入门到放弃系列 四】数据结构应用场景

List类型

list的核心特点是顺序性,主要是其底层实际上是一个双向链表结构:
【Redis从入门到放弃系列 四】数据结构应用场景

基本操作

其实由于其双向链表的灵活性,很容易模拟出栈或者队列的模式,因为我们查询时是从左边查询的,所以我们一般的使用策略是,从右边进入,这样从表面上看符合进入顺序的,比较直观【队列】
【Redis从入门到放弃系列 四】数据结构应用场景
需要注意的是查询索引:Start 只能为0,stop为-1就是倒数第一个,为-2就是倒数第二个

扩展操作【应用场景】

list的主要特性是顺序性,我们看基于这样的特性,常用的有哪些场景呢?

  • 场景六:利用blpop特性实现任务队列
  • 场景七:利用list顺序特性实现朋友圈点赞
  • 场景八:利用list顺序特性进行分布式日志顺序性展示

我们来看看这三个业务场景。

场景六:利用blpop特性实现任务队列

轮询从任务队列里取数据【可以同时从多个队列获取】,如果取到数据就返回,如果没有数据就等待设置时间持续获取,直到数据过期。
【Redis从入门到放弃系列 四】数据结构应用场景
一直等【从若干个列表中去等】,只要有数据就返回来
【Redis从入门到放弃系列 四】数据结构应用场景

场景七:利用list顺序特性实现朋友圈点赞

因为点赞等信息都是有顺序性的,而且修改的效率高,适合使用list来操作
【Redis从入门到放弃系列 四】数据结构应用场景
取消点赞的时候使用如下命令操作:
【Redis从入门到放弃系列 四】数据结构应用场景

场景八:利用list顺序特性进行分布式日志顺序性展示

使用list顺序性实现多路数据汇总展示,利用其栈的特性实现最新的消息最先展示。
【Redis从入门到放弃系列 四】数据结构应用场景

操作规范

list主要有如下几种使用规范:
【Redis从入门到放弃系列 四】数据结构应用场景

Set类型

因为list的查询效率太低,所以需要新的数据模型来进行支持,Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据

【Redis从入门到放弃系列 四】数据结构应用场景
那么为什么我们的值不允许重复呢?,不支持vaule重复录入,因为我们原来hash里的field也不允许重复
【Redis从入门到放弃系列 四】数据结构应用场景

基本操作

set的操作相对简单,主要明确一点,set里不会有重复数据
【Redis从入门到放弃系列 四】数据结构应用场景

扩展操作【应用场景】

set的主要特性是不重复性,我们看基于这样的特性,常用的有哪些场景呢?

  • 场景九:利用set特性随机获取不重复数据实现简单推荐系统
  • 场景十:利用set交并差实现推荐系统池
  • 场景十一:利用set不重复特征获取所有业务系统权限
  • 场景十二:利用set不重复特征获取UV和IP数据
  • 场景十三:利用set不重复特征实现黑白名单

我们来看看这五个业务场景。

场景九:利用set特性随机获取不重复数据实现简单推荐系统

【Redis从入门到放弃系列 四】数据结构应用场景
可以使用如下命令:
【Redis从入门到放弃系列 四】数据结构应用场景

场景十:利用set交并差实现推荐系统池

【Redis从入门到放弃系列 四】数据结构应用场景
可以使用如下命令实现:

【Redis从入门到放弃系列 四】数据结构应用场景
总而言之就是实现数据的关联差异:
【Redis从入门到放弃系列 四】数据结构应用场景

场景十一:利用set不重复特征获取所有业务系统权限

【Redis从入门到放弃系列 四】数据结构应用场景
我们可以设置用户为一个set集合,他的权限为value,然后合并所有用户就可以拿到所有不重复权限
【Redis从入门到放弃系列 四】数据结构应用场景

场景十二:利用set不重复特征获取UV和IP数据【Redis从入门到放弃系列 四】数据结构应用场景

我们可以采用将ip或者cookie放到set中保证不重复,对同类型数据进行快速去重
【Redis从入门到放弃系列 四】数据结构应用场景

场景十三:利用set不重复特征实现黑白名单

【Redis从入门到放弃系列 四】数据结构应用场景
实现时把对应黑白名单信息源添加到set中即可。
【Redis从入门到放弃系列 四】数据结构应用场景

操作规范

【Redis从入门到放弃系列 四】数据结构应用场景

Sorted_Set类型

redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。有序集合的成员是唯一的,但分数(score)却可以重复。
【Redis从入门到放弃系列 四】数据结构应用场景

基本操作

操作都是关联score的,获取时按照score值来进行排序获取。
【Redis从入门到放弃系列 四】数据结构应用场景
同时需要注意,删除的时候按照值删除,而不是按照score删除。
【Redis从入门到放弃系列 四】数据结构应用场景
【Redis从入门到放弃系列 四】数据结构应用场景

扩展操作【应用场景】

sorted_set最经典的应用场景就是进行排行榜设置了。当然除此之外还有些带权重的操作都类似:

  • 场景十四:利用set不重复排序特征实现计数器组合排序排行榜功能
  • 场景十五:利用set不重复排序特征实现基于时效性任务提醒
  • 场景十六:利用set不重复排序特征实现带权重任务队列

接下来看下这三种场景

场景十四:利用set不重复排序特征实现计数器组合排序排行榜功能

【Redis从入门到放弃系列 四】数据结构应用场景
可以利用如下命令直接获取排名
【Redis从入门到放弃系列 四】数据结构应用场景

场景十五:利用set不重复排序特征实现基于时效性任务提醒

【Redis从入门到放弃系列 四】数据结构应用场景
队列中全部为vip,按照会员时间长短排序,短时间到期后提醒下一个。
【Redis从入门到放弃系列 四】数据结构应用场景

场景十六:利用set不重复排序特征实现带权重任务队列

仅是任务队列可以通过队列,但是如果队列中的任务有优先级,则需要使用带权重的。
【Redis从入门到放弃系列 四】数据结构应用场景

操作规范

【Redis从入门到放弃系列 四】数据结构应用场景

总结

通过一周的学习终于从场景的角度更深入的理解了redis的使用,基于这周的学习内容,依据redis的不同数据结构的特性,再次梳理下场景:

  • string,redis对于KV的操作效率很高,可以直接用作计数器。例如,统计在线人数等等,另外string类型是二进制存储安全的,所以也可以使用它来存储图片,甚至是视频等。【计数器、分布式自增、分布式锁、热点数据刷新】
  • hash,存放键值对,一般可以用来存某个对象的基本属性信息,例如,用户信息,商品信息等,另外,由于hash的大小在小于配置的大小的时候使用的是ziplist结构,比较节约内存,所以针对大量的数据存储可以考虑使用hash来分段存储来达到压缩数据量,节约内存的目的,例如,对于大批量的商品对应的图片地址名称。比如:商品编码固定是10位,可以选取前7位做为hash的key,后三位作为field,图片地址作为value。这样每个hash表都不超过999个,只要把redis.conf中的hash-max-ziplist-entries改为1024,即可。【数据对象存储、秒杀系统、分布式锁】
  • list,列表类型【顺序性】,可以用于实现消息队列,也可以使用它提供的range命令,做分页查询功能。【任务队列、社交点赞、分布式日志顺序显示】
  • set,集合,整数的有序列表可以直接使用set。可以用作某些去重功能,例如用户名不能重复等,另外,还可以对集合进行交集,并集操作,来查找某些元素的共同点。【推荐系统、数据去重、运营数据统计、黑白名单】
  • Sorted_Set,有序集合,可以使用范围查找,排行榜功能或者topN功能。【排行榜】

总而言之,string当做计数器,hash存储对象,list实现消息队列(安全队列),set用来去重和联表查询,zset用来做排行榜。