前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >难道程序员只把Redis当缓存?3大场景助你完美收割Redis实战开发

难道程序员只把Redis当缓存?3大场景助你完美收割Redis实战开发

作者头像
xcbeyond
发布2020-03-25 14:44:10
7390
发布2020-03-25 14:44:10
举报
文章被收录于专栏:技术那些事技术那些事

微风拂面只在瞬间,如若没有对这一刻的思索,往往少许了些对于问题本质的思考、推敲,这一刻的感受,将不会激荡起心灵中对于本质的追寻。而后渐渐得将失去对于任何事物的看法,仅仅在自己的认知圈里面找到所认知的方案,从而忽视了对与更好事物的探索。

缓存操作就看String,这是为什么?

程序员对缓存并不陌生,但对于Redis的非关系型数据中的使用,恐怕大家就只有String这一数据类型来做到过使用。但是Redis本身就是拥有多种数据类型的缓存数据库,并不单独只有String一种数据类型,同时String中能解决的业务问题并不只有缓存,还有其它高级应用场景。那为什么一般都不去考虑到其它数据类型与应用场景呢?

原因大致有如下三点:

  • 顾名思义,以非关系型数据而谈

Nosql数据库界下的Redis、memcache、MongoDB等,都是非关系型数据库来存储数据,那什么是非关系型数据库呢?

像MySQL关系型数据库查找的数据是按照行来表示记录的,每一行下由多个列来进行组成,可以发现每一行里面的数据都是由各个列的数据共同组合而成。每一列的数据对于该行数据进行关系属性的补充,这就是关系型数据库的特点。

非关系数据库的数据查找就不需要像MySQL那样基于关系的列来组合构成的数据,而是直接获取对应的数据。常用的非关系模型有如下:

列模型:存储的数据是一列列的。列模型数据库以一列为一个记录。(这种模型,数据即索引,IO很快,主要是一些分布式数据库。例如:HBase

如上是HBase表的存储结构模型,其中有4个字段。分别为Rowkey(主键)、Time Stamp(时间戳)、CF(列族)、CF:xx(列)。

根据每一列来保存数据,需要修改就做调整。存储如下:

键值对模型:存储的数据是一个个“键值对”,比如K1:V1,那么K1这个键里面存的值就是V1

文档类模型:以一个个文档来存储数据,有点类似“键值对”。采用JSON的格式来存储数据库,需要就直接来更改内部里面缓存文档里面属性即可。(目前Mysql5.7以后也支持了JSON格式数据的查询)

  • 列模型:Hbase
  • 键值对模型:redis,Memcache
  • 文档类模型:mongoDB

基于非关系的特点在使用的过程中,更多的是基于键值对方式来做缓存存储,其它的String操作方式也不了解,与业务条件也没有挂钩的地方。恰好有的场景下面就需要关系型的业务才可操作,也就没考虑到Redis。

  • 项目太小,用不到一些场景

都说环境决定一个人的行为习惯,如果项目的规模比较小,根本就需要太过高级的场景使用即可满足业务的要求,在这样的情况下,就只是使用Redis的缓存String结构做缓存。

并且String可以支持很多结构特点的数据来进行操作,数据少直接key->value。多一点json序列化然后保存,直接解决了问题。所以就没有过多的考虑到其它业务条件下的使用方案。

  • 对项目问题,不会带入所学知识

Redis下面提供的丰富的数据类型来供业务操作可选,但自身对于业务要求并不是很熟悉,也没了解的业务的构成。就不会考虑到其它的Redis的数据类型具备的特点。学了不代入到场景,那么下次遇到的问题肯定还不会采用Redis的使用。

这也是为什么代入知识到场景之前,需要对Redis的数据结构有到一定的了解,这样才知道对应的业务的数据是如何存储。详细数据类型结构分析请点击如下链接查看

网站接入Redis缓存,你真的会用吗?Redis原理分享,从使用到会用

善于发现String的其它用法,问题将迎刃而解

想要打破墨守成规的使用方案,就需要去发现string的其它用法,只有知晓它的模式特点,才能更好的类比于业务。

String在默认使用缓存数据的时候就是按照Key->Value的格式来进行存储的,而String基本可满足于任何业务场景,直接存储到数据里面,然后根Key进行获取。所以在选择String的时可判断哪些场景是随用随取的效果。并且存储的数据变化上也不是特别大。例如:页面缓存、全国地区等

如果是一些结构化数据处理的业务,需要通过在数据库里面进行条件的组合筛选,并且里面的数据经常以变更。那么采用string就不太适合了,因为它太单一,灵活性不够,例如:排行榜、投票的业务。对于这块业务数据,更应该采用Redis其它灵活的数据类型来进行组合式的操作。

对String操作的数据内部分别有字符串、数字、二进制的区分,区分后在选择也就可以更加的具体选择到项目中出现这些类型的方案

Redis的字符串,场景化有那些

字符串是项目使用最多的数据类型,毕竟这个网站数据最多呈现的就是中文、因为等各国不同语言,这些语言呈现就是用到字符串。

字符串可以分为简单字符串与复杂字符串(xml、json)两大类

简单字符串:就是指一般普通的字符,就是存储一些文字上表述内容,平常操作最多的就是简单字符串。

字符串

一般场景如下:

1、缓存层,符串最经典的使用场景,就是把一些不怎么变动的数据提取到Redis当中,从而减少网络请求进入到Mysql数据中。后面Redis做缓存层,MySQL做存储层。

2、分布式session会话

当我们用nginx做负载均衡的时候,如果我们每个从服务器上都各自存储自己的session,那么当切换了服务器后,session信息会由于不共享而会丢失,我们不得不考虑第三应用来存储session。通过我们用关系型数据库或者redis等非关系型数据库。关系型数据库存储和读取性能远远无法跟redis等非关系型数据库。

如果是单体架构也是可以采用Redis做会话存储,从而来提升网站会话的获取速度。

如果大家看过session存储的默认的文件存储结构,就知道其实内部也是json序列化后的信息,但对于PHP开发来说,你的操作也是键值对的形式,通过$_SESSION来进行操作,在session底层方法内部再去修改存储结构的数据。这也是大家需要明白的。

3、分布式锁

分布式锁,是一种思想,它的实现方式有很多。是为了解决在并发编程中,通过锁机制,来避免由于竞争而造成的数据不一致问题。每次请需取到锁,再来执行业务,没得就直接返回请求

例如:从前端界面发起一笔支付请求,如果前端没有做防重处理,那么可能在某一个时刻会有二笔一样的单子同时到达系统后台

代码语言:javascript
复制
采用如下命令:
SET lock_key random_value NX PX 5000
值得注意的是:
random_value 是客户端生成的唯一的字符串。
NX 代表只在键不存在时,才对键进行设置操作。
PX 5000 设置键的过期时间为5000毫秒。

在这里我们采用SET NX参数命令是为了防止setnx和exprie过程中,因为进程挂掉,而导致死锁。

4、时间序列

采用APPEND 可以为一系列定长(fixed-size)数据(sample)提供一种紧凑的表示方式,通常称之为时间序列。

每当一个新数据到达的时候,执行以下命令:

APPEND timeseries “fixed-size sample”

然后可以通过以下的方式访问时间序列的各项属性:

  • STRLEN 给出时间序列中数据的数量
  • GETRANGE 可以用于随机访问。只要有相关的时间信息的话,我们就可以在 Redis 2.6 中使用 Lua 脚本和 GETRANGE 命令实现二分查找。
  • SETRANGE 可以用于覆盖或修改已存在的的时间序列。

这个模式的唯一缺陷是我们只能增长时间序列,而不能对时间序列进行缩短,因为 Redis 目前还没有对字符串进行修剪(tirm)的命令,但这个模式的储存方式还是可以节省下大量的空间。

可以考虑使用 UNIX 时间戳作为时间序列的键名,这样一来,可以避免单个 key 因为保存过大的时间序列而占用大量内存,另一方面,也可以节省下大量命名空间。

代码语言:javascript
复制
redis> APPEND ts "0043"
(integer) 4
redis> APPEND ts "0035"
(integer) 8
redis> GETRANGE ts 0 3
"0043"
redis> GETRANGE ts 4 7
"0035"

复杂字符串:就是针对结构化的数据存储,一般用于XML、JOSN的数据格式。

结构化数据:指像数组、对象等这些类型的数据,和普通的字符串组成有很大区别。

常用场景如下:

  • 结构化数据,有时候如果需要存储结构化数据,且这样的结构数据变动不大,就可以采用,因为比较方便简洁。
代码语言:javascript
复制
例如:像数据库查询出来的菜单栏,这个很少变化。把查询出来的对象直接序列化,存储起来,使用的时候取出来即可。
  • 静态化页面

做过项目的同学都知道,页面的静态化可以帮助搜索引擎更好的抓取和访问加速,而不在后端进行模板的渲染后,在响应到客户端进行DOM的解析。

代码语言:javascript
复制
例如:做到这个操作首先需要读取整个网页的数据,然后把数据序列化保持到Redis里面。到时候更加网站打开的对应地址为Key,直接读取。这样就不在有数据库什么事情

数字类型场景

数字场景最简单明显,就关于数量相关的数据存储,用于展示出具体的数量单位

  • 限速:出于安全、性能考虑,公开限制 API 的请求次数,会对一些访问获取的数据接口进行相关的限制,防止别人恶意的访问接口,或者是别人采用多线程调用接口而导致接口大量操作从而导致服务器压力过大。
代码语言:javascript
复制
例如:每次进行登录时让用户输入手机验证码,为了短信接口不被频繁访问,会限制用户每分钟获取验证码的频率。

实现思路:
可以通过组合使用 INCR 和 EXPIRE ,来达到只在规定的生存时间内进行计数(counting)的目的。
客户端可以通过使用 GETSET 命令原子性地获取计数器的当前值并将计数器清零,
使用其他自增/自减操作,比如 DECR 和 INCRBY ,用户可以通过执行不同的操作增加或减少计数器的值,比如在游戏中的记分器就可能用到这些命令。
  • 计数器:许多运用都会使用redis作为计数的基础工具,可以实现快速计数、查询缓存的功能,同时数据可以一步落地到其他的数据源。
代码语言:javascript
复制
例如:像网站中的主页的访问量、点击量、浏览器等相关计算的内容都可以,简单点就是做统计处理。
incr userid:pageview (单线程 : 无竞争)

redis是天然适合做计数器的,因为是单线程的,所以并发执行incr的时候不会有竞争问题,无论并发量多大都不会记错数。
  • 分布式id生成器:在复杂分布式系统中,往往需要对大量的数据和消息进行唯一标识,数据库的自增ID显然不能满足需求。因为并发写的时候可能会导致锁表的问题,还有效率也提升不起来。同时插入过程中数据库会开启一个隐含的事务,需要你提交后才可以让ID生效。
代码语言:javascript
复制
incr id (原子操作)
仍然可以使用incr这样的命令来实现,实际的实现方案会比这个要复杂一些,但是最基础的一个实现的思路或者原理都是使用这样一个规则。例如:Twitter的Snowflake算法

二进制数据使用场景

String类型是二进制安全的,就是可以存储到任意类型的数据。虽然大家接触到的图片、视频、文件都是和普通编程里面的字符串有很大区别。但是这些文件的背后都是由二进制文件组成的。只是在Windows电脑上面是以对应文件格式的软件识别读取出来的。

放眼到程序中,保持二进制文件的内容就是把(视频、图片、文件)的内容以二进制格式的方法读取出来。然后把它存储到Redis中。用到的还是key->value的格式,数据不怎么变化的非关系数据。

注:读取的方式就是用fopen之类的函数文件打开口,读取的时候以二进制来做就可以了。相对来说这种用的比较少,这样写入写出还是太麻烦了。

不思考有什么问题

任何的东西都是从开始接触到它,然后再应用到对应的场景中。如果不去注意到这些。那后面将会一直停滞到当前,还会少些挑战的乐趣。遇到什么问题基本没有什么更好的解决方案。也会失去更方便工具来简化开发的难度。往往吃亏的都是自己能力提升。

总结:

比起更多的应用场景,我更想带来的是大家场景化的随机应变解决能力。通过归类于各种数据类型的结构,在对应到实际的开发场景中里面。选择合适的工具。做到有理可寻。而不是凭借感觉来使用。毕竟开发中严谨是大于感觉的。如果做好归类于每个数据的特点,在进行开发就显得很简单明了。

欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章对你有所帮助,让你有新的启发,有新的认识,欢迎转发分享给更多人。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-10-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序猿技术大咖 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 缓存操作就看String,这是为什么?
  • 善于发现String的其它用法,问题将迎刃而解
  • 字符串可以分为简单字符串与复杂字符串(xml、json)两大类
  • 二进制数据使用场景
  • 不思考有什么问题
  • 总结:
相关产品与服务
对象存储
对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档