NoSQL那些事--Redis

Redis是个流行的内存数据库(in-momery)。接口好用,性能也很强,还支持多种数据结构,加上各种高可用性集群方案,实在是太太太好用了。

但是就是因为太好用了,好用到让很多人都晕了脑子:

  • 用Redis性能就大大提高了
  • 用Redis可以保证原子性
  • 用Redis可以实现事务
  • 用Redis可以当队列
  • ……

这就好像一个股民,在手机上操作买卖几笔股票,赚了一些,然后感叹道"股市就是为我发财而存在的啊"!!他的下场可想而知。

Redis的种种优势源自于他的设计——简单直接的单线程内存操作。但这些优势是有前提的。

Redis的性能高,吗?

Redis的性能非常高。有些评测说用Redis可以达到几十万QPS(比如这里http://skipperkongen.dk/2013/08/27/how-many-requests-per-second-can-i-get-out-of-redis/)。大家可能在网文上记住了这个NB的数字,却很少关心这个数值怎么来的。这就像是你买手机评测光看跑分一样不靠谱。

Redis要达到高性能需要做到:

  • Value尽可能的小。一般的测评都会用比较小的value,比如一个整数或者不长的字符串。但是如果用Redis做缓存,那么缓存的大小的可能偏离这个数字。比如一个页面几十KB;再比如,一个5年的市场价格序列数据可能高达几MB。这么大的数据量在带宽的限制下直接的效果就是QPS骤降,跌到几百都毫不意外。毕竟Redis不是神仙,不能改变物理定律。此外,因为Redis是单线程的,过大尺寸的数据访问会block所有其他的操作。
  • 使用Pipeline或Lua Script。Redis一般被用做网络服务。所有的请求都是跨网络进行的。所以TCP Round Trip的长短对Redis的性能表现很重要。尽量减少Round Trip可以有效的提高吞吐。所以,通常的优化方法是使用Pipeline,使得客户端可以一次性把一组Redis命令发给Redis Server;或者预先在Redis Server中定义Lua Script,使用时直接调用。但无论是Pipeline还是Lua Script,都会受到业务需求的制约——不是所有业务都适合用Pipeline/Lua Script的。
  • 使用快一些的网络。很多Redis的测评为了彰显其NB,都是在本地同时跑客户端和服务器的。也就是说,它们要么使用了loopback网络(localhost),要么使用了Unix Socket。这根本就不能反映一般分布式的网络场景下的情况。同时,一些Redis的HA/Sharding方案会选择用Twemproxy这样的代理来实现。代理的加入会让性能进一步的打折扣。
  • 不开启RDB或者AOF。RDB和AOF是Redis的持久化方案。开启他们会对Redis的性能表现有损耗。比如RDB在开始执行时,会fork一个新的用于写入rdb文件的进程。这个fork的过程和内存空间的复制会让Redis卡顿一下;AOF每次sync数据到磁盘,也会block一小会。如果为了确保数据严格持久化,开启了AOF的appendfsync=everysec设置,使得每个写入指令都要立刻sync到磁盘,就会打破Redis快的前提——内存数据操作。简单来说,开启任何一种持久化方案都会影响Redis的性能表现。

所以,如果想真实评价Redis的性能,一定要把你的场景设计好,然后用Redis自带Redis-benchmark(见https://redis.io/topics/benchmarks),设定value的尺寸、要测试的Redis命令、和Pipeline的开启情况,再把Redis Server按照生产环境的样子配置好。然后跑一下压测,看看Redis的实际表现到底是怎样的。

Redis可以保证原子性,吗?

我们先定义一下什么是原子性:

  • 一般编程语言这么定义:原子性是指一组操作在执行过程中,不受其他并发操作的干扰。这样进行的数据操作的值不会被相互覆盖。
  • 数据库事务中ACID的A这么定义:原子性是指一组操作,要不完成,要不没做,不存在改了一半的状态。没完成的操作可以回滚。

很显然,Redis并不支持回滚,所以第二条肯定没戏。

那么第一条呢?

Redis是单线程执行的。在完成一个操作之前,不会有其他的操作被执行。这的确是真的。但是,在业务开发中,需要的不是一个简单操作的原子性,而需要实现一个临界区的原子性。

业务中对数据的操作往往都不是简单的一个set,一个incr就可以搞定的。一个复杂的业务逻辑,往往需要多个带有逻辑判断的写入指令。业务中要保证的是这一组指令是原子的。比如下面的逻辑,希望一个value只能越设置越大。

(async function setBiggerV(v) { let currentV = parseInt(await redis.get('key')); if (currentV < v) { await redis.set('key', v); } })(); 

这其实是有bug的,考虑到如下执行序列(假设v一开始是5):

client A:尝试将v设置为7client B:尝试将v设置为8
读取key,得到5 
 读取key,得到5
 设置key,为8
设置key,为7 

最终,Redis中v的值被设置为7,这就违反了这段逻辑的设计。如果这个机制被应用于协调一个分布式系统,那么整个系统就会因此挂掉。set这个命令是不是原子并不能让这段业务代码变成原子的。我们需要的是让get和set这个整体原子。

在Redis中,可以用Redis事务或者Lua Script来实现原子性。Redis事务和Lua Script都可以保证一组指令执行不受其他指令的打扰。比如上面的例子,用Lua Script实现,就可以正确运行。

但如果业务逻辑涉及到其他存储,Redis事务和Lua Script就帮不上忙。比如,在Redis中放一个库存的数字。用户下单时,要在Redis中扣减库存,并且在另外一个数据库中INSERT一条交易记录。这段逻辑是没法做到原子的——除非你自行实现了某种分布式事务的机制。而分布式事务的实现复杂度往往会超过Redis带来的好处。

用Redis可以实现事务,吗?

我们一般场景下说的事务的意思往往指的是数据库系统中的”ACID事务“。(见https://www.jianshu.com/p/cb97f76a92fd)。ACID事务是计算机科学中一个非常重要的抽象。它极大地简化了编写业务代码的难度。没有ACID事务,开发人员需要花大量精力处理由于并发和系统意外崩溃带来的数据一致性问题。

Redis也有一个“事务”的概念。原文(见https://redis.io/topics/transactions)。大致含义是:Redis将MULTI指令和EXEC指令之间的多个指令视作一个事务;一旦Redis看到了EXEC就开始执行这一组指令,并保证执行过程中不被打断——除非Redis本身或者所在机器crash掉。如果发生了,就可能出现只有部分指令被执行的情况。

所以,Redis事务与ACID事务是完全不同的!

Redis的事务只支持Isolation,不支持ACD。

有人说,AOF的appendfsync=everysec是可以持久化的。但这种持久化只在单机情况下有效。多机情况下,Redis是没有一个机制能够将数据修改同步sync到其他节点的,即便是Redis Cluster的WAIT指令也不行。

在这种限制下,在Redis中实现业务逻辑差不多就只有两种可能:

  • 不在意ACID事务——数据丢了没事,改错了也没大关系
  • 基于Redis的接口实现自己的ACID,或者ACID的某种子集

缓存属于第一个场景。数据丢了没事,从数据库里重新加载就行了。

但如果是第二种场景,你要自己搞一个ACID。不是不可能,但要反复确认这样做的必要性。你是否具有专业的存储开发技能,你能投入多少精力在ACID上,你的公司能给你多少资源做开发测试,这些都需要仔细考虑。

用Redis可以当队列,吗?

Redis实现了一个List的数据结构。借助它,可以实现出队,入队的功能。实际上很多人早就熟练使用Redis做队列。比如Sidekiq就是使用Redis作为异步job队列的存储。然而,这样靠谱吗?

靠谱不靠谱,得看你怎么定义“队列”的要求:

  • 队列可不可能丢东西?比如,如果队列短时间挂掉。此时,producer是必须停止服务,还是继续服务但不再插入队列(这样就会丢东西),或者说producer有某种机制可以在本地先暂时堆积一下,直到队列恢复工作?
  • 队列的consumer是否需要一个“commit”的语义,表示处理完了一个事件?还是说,只要从队列里取出来就可以了,万一没处理也没所谓?
  • 是否有事件重放的需要?比如上线了一个版本的consumer然后发现有bug,处理错了3个小时的数据。修复后,希望能重新处理一遍之前出错的数据,那么这个队列能不能做事件的”重放“?
  • 如果consumer处理失败怎么处理?是直接丢弃,还是重新插入到队列中?
  • 队列是不是需要有最大的长度限制?如果到了最大长度,说明Consumer跟不上Producer的速度;此时,需要卡住Producer吗?
  • ……

Redis的List基本上对于所有这些问题都是完全不管的。也就是说,它不能给你任何的保证。更严重的是,就算你能接受一定程度的数据丢失,但是Redis无法告诉你他丢了多少东西,并且找不回来(MySQL还能翻翻binlog)!到最后,到底丢了多少,造成多少损失,是无法监控,是无法衡量的。

在业务上,“保证”一个事情能够发生相当重要。试想一下,你的界面允许用户下一笔订单,用户已经看到了“成功下单”的界面,结果之后却发现什么订单也没有。用户是不是有一句MMP不知道当讲不当讲。

也许,你会说,"我的场景不需要这么严格的一致性,数据丢了没所谓,也不需要事件重放,数据处理错了就错了"。这个Redis的确可以办到,而且可以做得很好。但我建议你和你的产品经理聊一下,看看需求是不是真的这样。也许他会有不同的意见 ; - )

一般来讲,一个技术公司需要两大类“队列”。一种是业务事件队列。这种队列绝对不能丢东西,而且可能需要exactly once语义,需要高可用。为了保证可用性,多节点的部署是必须的。而引入了多节点,就必须解决复制的问题和分布式一致的问题,主从切换的问题,分片的问题等。这种队列的典型代表是Rabbit MQ和Kafka。

另外一种队列是收集服务前后端业务事件的队列(比如登陆、注册、下单成功、下单失败……)。通过队列,这些事件会被收集到数据分析中心,支持错误分析、客服、数据分析等功能。这种队列可以容忍一些数据丢失,也能容忍数据延迟性比较大,但要求吞吐巨大。这种队列的典型代表是Fluentd和Logstash。

也许你一开始在用Redis的List做队列,但是如果这个业务是认真的,你的系统一定会逐渐演进到这二者之一。

Redis 4.2计划引入Disque作为新的队列实现。也许能够扭转这个情况。但4.2离发布还要很久,并且成熟到可以在生产使用,也至少要到4.4版本——大概在2019年甚至更晚。所以目前观望一下就好,不必特别在意。


更新一下:Redis 5.0beta引入了Stream Date Type。实现了类似于Kafka的append only数据结构和API。不过很可能要到5.2才能在生产中使用(2019年年底)。见https://redis.io/topics/streams-intro


Redis适合用来做什么?

在我看来,Redis适合以下场景:

  • 共享Cache ,不怕丢数据,丢了可以从DB中reload;
  • 共享Session ,不怕丢数据,丢了可以重新登录;
  • batch job的中间结果。不怕丢数据,丢了重新跑job就可以了;
  • 一些简单数据的存储,低频改动,但是会被频繁读取。比如首页推荐的产品列表。但此时必须增加HA的防护,sentinel、cluster或者自定义的机制都可以;
  • 一些更加复杂存储的building block,比如分布式锁,此时需要多节点来实现一个简单的quorum

其他场景,往往有更好的、更成熟的方案。

特别注意,不要用Redis存储任何需要“认真对待”的数据,请用支持ACID事务的数据库。

Redis是非常优秀的工具,但非是银弹。只有认真的了解业务对“保证”的要求,认真的了解所用工具的工作原理,才能做出正确的设计决策。

转载:https://www.jianshu.com/p/9cecff6042de

转载于:https://www.cnblogs.com/boxy/p/11533553.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/482374.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

柳昀哲课题组在Nature Reviews Neuroscience上发表长篇综述提出表征富集理论

来源&#xff1a;北师大脑与认知科学“读心解梦”一直以来是人们追求的梦想&#xff0c;从佛洛依德对于潜意识意义的追寻&#xff0c;到当今神经科学的神经信号解码&#xff0c;人们采用主观或客观的方式理解人类高级智能的脚步从未停止。早期人们理解人类意识的内涵&#xff0…

Excel生成Sql语句 格式如:=字符串1A2字符串2C2字符串3

我们有时候需要根据Excel生成sql语句&#xff0c;可以利用Excel的字符串拼接&。格式如&#xff1a;"字符串1"&A2&"字符串2"&C2&"字符串3" 例如&#xff1a;在一个Excel中&#xff0c;我们要在Data_Company表中&#xff0c;根…

诺奖10年,干细胞领域再突破!华大单细胞技术助力获得人类体外诱导全能干细胞...

来源&#xff1a;生物探索题图来源&#xff1a;The Baltimore Sun排版&#xff1a;文竞择近日&#xff0c;中国科学院和深圳华大生命科学研究院等多家机构的研究者&#xff0c;通过体细胞诱导培养出了类似受精卵发育3天状态的人类全能干细胞&#xff0c;这是目前全球在体外培养…

Django - 模板相关

一.MVC和MTV 1. MVC M: Model : 数据库, 存取数据 V: View: 视图, 信息的展示 C: Controller: 控制器, 逻辑的控制, 负责调度, 传递指令 2. MTV M: model: ORM操作 T: Template: 模板, HTML V: View: , 视图, 业务逻辑相关 二. 变量 {{变量名}} 由字母和下划线组成 (.) def te…

低代码公司黑帕云被字节跳动收购:潮水褪去,曾经爆火的低代码赛道迎来变局?...

来源&#xff1a;AI前线作者&#xff1a;凌敏曾经站在风口的低 / 无代码创业&#xff0c;如今风光不再&#xff1f;低代码公司黑帕云宣布停服&#xff0c;创始人入职飞书3 月 20 日&#xff0c;低 / 无代码创业公司黑帕云宣布&#xff0c;公司将于 2022 年 5 月 31 日停止服务&…

秒懂系列 | 史上最简单的Python Django入门教程

http://www.cnblogs.com/baiboy/p/django1.html 摘要&#xff1a;Django的学习教程也是分门别类&#xff0c;形式不一。或是较为体系的官方文档&#xff0c;或者风格自由的博客文档&#xff0c;或者偏向实例的解析文档。即使官方文档&#xff0c;章节较多&#xff0c;文字阐述累…

清华大学和MIT研究人员使用DeepMind的AlphaFold方法来增强COVID-19抗体

来源&#xff1a;ScienceAI编辑&#xff1a;绿萝利用 DeepMind 先进的蛋白质知识&#xff0c;清华大学的科学家们设计出能够抵抗 COVID-19 免疫逃逸的突变单克隆抗体。2020 年底&#xff0c;AlphaFold 2 的问世震惊了结构生物学界&#xff0c;AlphaFold 2 是谷歌人工智能部门 D…

【秒懂】号称最为简明实用的Django上手教程

https://www.cnblogs.com/baiboy/p/django1.html 阅读目录 1 几个基本概念 2 Django配置准备3 Django基础配置安装摘要&#xff1a;Django的学习教程也是分门别类&#xff0c;形式不一。或是较为体系的官方文档&#xff0c;或者风格自由的博客文档&#xff0c;或者偏向实例的解…

马斯克:今年占全球发射质量65%,星舰5月或首次轨道试飞

来源&#xff1a;澎湃新闻 作者&#xff1a;张静 马斯克透露&#xff0c;星舰有望5月开展首次轨道飞行测试&#xff0c;SpaceX计划今年的发射占全球发射质量的65%左右&#xff0c;“粗略计算是16吨*50次发射800吨。”3月22日&#xff0c;马斯克在社交媒体上表示&#xff0c;星舰…

spring boot 配置文件加密数据库用户名/密码

这篇文章为大家分享spring boot的配置文件properties文件里面使用经过加密的数据库用户名密码&#xff0c;因为在自己做过的项目中&#xff0c;有这样的需求&#xff0c;尤其是一些大公司&#xff0c;或者说上市公司&#xff0c;是不会把这些敏感信息直接透露给你&#xff0c;尤…

菲利普·安德森:凝聚态物理的艺术家

来源&#xff1a;集智俱乐部作者:Andrew Zangwill 译者:董唯元 审校:梁金 编辑:邓一雪 导语物理学家P.W.安德森&#xff08;Philip Anderson&#xff09;因无序和磁性材料方面的工作获得1977年诺贝尔物理学奖&#xff0c;但这并不足以彰显他的贡献。他推动多体理论与固体物理的…

清华刘知远:大模型「十问」,寻找新范式下的研究方向

来源&#xff1a;智源社区作者&#xff1a;刘知远整理&#xff1a;李梦佳大模型的出现迎来了AI研究的新时代&#xff0c;其所带来的结果提升十分显著&#xff0c;超越了很多领域中针对研究问题设计特定算法实现的提升。具体而言&#xff0c;预训练到Finetune的新范式最本质的特…

Django - ORM操作

Django - ORM操作 一. 必知必会13条 单表查询之神奇的双下划线二. ForeignKey操作 正向查找反向操作三. ManyToManyField四. 聚合查询和分组查询 聚合分组五. F查询和Q查询 F查询Q查询六. 锁和事务 锁事务七. Django ORM执行原生SQL 执行原生查询直接执行自定义SQLDjango - ORM…

从王者荣耀AI看人工智能与游戏结合的未来意义

来源&#xff1a;央广网国际在线消息&#xff1a;3月18日&#xff0c;成都大运会倒计时100天之际&#xff0c;由大运会执委会主办&#xff0c;腾讯承办的“世界大学生数智竞技邀请赛”正式启动。这次邀请赛将融合科技、文化、竞技的赛场精神&#xff0c;以《王者荣耀》和腾讯AI…

String源码分析

最近开始阅读java底层的源码&#xff0c;是因为发现越到后面越发现读源码的重要性&#xff0c;真的很重要&#xff0c;不阅读源码&#xff0c;你会发现“路”越走越窄。 今天看到了String的这个构造方法&#xff0c; /*** Initializes a newly created {code String} object so…

575万奖金!2022年数学界「诺贝尔奖」发布,拓扑学大师获奖

来源&#xff1a;AI科技评论作者&#xff1a;西西编辑&#xff1a;陈彩娴3月22日晚&#xff0c;被誉为数学界「诺贝尔奖」的阿贝尔奖揭晓。2022年&#xff0c;挪威科学院决定将阿贝尔奖授予来自美国纽约市立大学研究生院的阿尔伯特爱因斯坦讲座教授、纽约州立大学石溪分校的教授…

为什么深度学习是非参数的?

来源&#xff1a;AI科技评论作者&#xff1a;Thomas Viehmann编译&#xff1a;钱磊编辑&#xff1a;陈彩娴今天我想要与大家分享的是深度神经网络的工作方式&#xff0c;以及深度神经与“传统”机器学习模型的不同之处。我的计划具体如下&#xff1a;首先简单地思考一下如何将问…

“一束光”让机器人也能拥有触觉?之江实验室这项技术惊艳世界

来源&#xff1a;浙江日报传递触觉的“特殊道路”我们对这个世界最初的感知通常是从触觉开始的——第一声啼哭之前&#xff0c;婴儿经历过诱发哭声的拍打&#xff1b;成长中提笔、拍球&#xff1b;生活中握手&#xff0c;敲击键盘&#xff0c;使用手机……触觉充斥着我们日常生…

图书管理系统~简单流程

1. 连接数据库 2. 路由url (网站目录) 2.1若要从URL 中捕获一个值&#xff0c;只需要在它周围放置一对圆括号。&#xff08;分组&#xff09;2.2使用简单的、没有命名的正则表达式组&#xff08;通过圆括号&#xff09;来捕获URL中的值并以位置 参数传递给视图。在更高级的用法…

7年前轰动全球的Science论文,被发现可能搞错了

来源&#xff1a;iNature蛇是一个非常多样化和成功的群体&#xff0c;但它们的进化起源是模糊的。两条腿蛇的发现揭示了从蜥蜴到蛇的过渡&#xff0c;但没有描述过四条腿蛇&#xff0c;早期蛇的生态知之甚少。2015年7月24日&#xff0c;英国朴茨茅斯大学David M. Martill等人在…