一篇关于Redis的好文章
Redis作为缓存使用,在值大小为1k的情况下,可以支持到每秒近十万次的set操作,可见redis的运行效率是非常的高的。但是为什么我们还会有的时候会遇到redis的瓶颈呢?一般来说,都是因为我们没有对redis的所有的操作有一个全面直观的了解。
Redis运行模式
Redis是运行在单线程下的,也就是说,一个redis实例最多也就只能占用一个cpu,当redis实例线程运行所使用的cpu到达100%后,就无法进行更多的操作了,甚至从操作系统层面就开始拒绝连接了。然后我们就遇到了最迷茫的事情,为什么我设置了很多的连接,但是都无法连接到redis服务呢,原因大抵如此。
Redis在执行一个操作的时候,其他所有的操作,包括系统的,后台的等等,都会出现阻塞,一旦有阻塞,就会出现返回变慢的情况。
虽然说redis的运行时非常快的,但是也会受到很多其他因素的影响,在分析过程中,要注意都有什么耗时的操作在霸占cpu(依旧是单线程的问题),这些操作能不能分解,这些操作能不能再做缓存,这些操作是否是必要的,在优化处理时都应该考虑这样的问题。
总而言之,redis是以单线程来应对上层多线程的调用,在编码过程中,使用到redis就要考虑到这一层。
Redis操作中需要规避的一些问题
Redis提供了比较多的数据结构,让单纯的kv结构更加丰富,但随之而来的问题就是,数据结构越是复杂,操作时间越长,记住redis只能单线程!
当然,redis就是为了大量快速地读写一些数据而生的,放心大胆地去用,不然搭建一个redis干嘛呢?
为了放心地使用redis,下面列举一些需要特别注意,必要时要规避这些操作。这些操作有时会很慢,但是具体有多慢呢?我们不能用通常的模式去理解,如果说这个操作只需要10ms呢?是否算慢呢?当一个操作需要10ms时,这个redis的实例,在1s中只能执行100次同样的操作,这样算快还是慢呢?当redis的调用量上来以后,这个操作就成了系统的瓶颈了。
SISMEMBER
这个操作是查看集合中的成员。在集合较大的情况下,会变得比较慢。所以,一般不要直接返回整个集合中的成员,而是采用标准的调用方式SISMEMBER key member,查看集合是否具有该成员,从而避免大量的无用的数据处理。
SINTER
返回一个集合的全部成员,该集合是所有给定集合的交集。当两个巨大的集合进行交集的运算,其效果也可以是毁灭性的。
LPUSH & RPUSH
在队列头部/尾部插入一串key。这个操作本身并无什么大问题,但是我们又考虑到redis是一个单线程,那么我们一次性插入了大量的值,就会造成阻塞,那么就有必要把这一次操作分散为多次的操作,循环去做了,虽然觉得循环会耗时,但是在没有读写分离的情况下,这种处理方式总归是比直接阻塞redis要来得好的。建议一次性增加200个左右为佳。但是这也受限于key值的大小。具体的问题具体分析,在调试和测试中要注意这部分的耗时,可以控制在10ms以内即可(redis默认超过10ms的操作对于redis是慢的)。
MSET & MGET
批量设置和获取一串key的值。此操作与上面的也是一样的,要考虑到整体的耗时,在需要的时候要做到循环设置/获取,标准也是尽量控制一次操作在10ms以内。
KEYS
KEYS操作,查询并枚举redis中与给定规则相符的key。此物为大杀器,看似每个操作只需要40-70ms,在编码和功能性的测试中,根本无法感知到其带来的恶果,因为70ms实在是很难感知到到底有多长,但是用另一个指标来衡量,就很明显看出来了。取平均值,假设KEYS操作耗时50ms,那么一个redis实例的qps只有可怜的20,还是在不做其他动作的情况下。
此处要着重说明之前的一个线上问题的解决,就是因为KEYS操作引起,最后调用者临时做了读写分离,并且将redis的实例拉到了恐怖的21个才勉强支持起线上的调用量,堪称本司有史以来最豪华redis,并且这个还是在用户数没有暴增的情况下。
所以切记,KEYS是禁止使用的!(后续再新机房中的redis会直接改掉这个操作,具体怎么再来调用KEYS操作,我就不告诉你!)
CONFIG GET & CONFIG SET
非管理人员,禁止使用!
Redis需要注意的操作其实并不多,并且很多情况下,根本不会造成压力,但是这些情况都是需要在编码时注意的,去衡量并正确高效地使用redis。记住一句,我们是单线程!我们是运行在毫秒级别的服务!
Redis的设计中需要注意的
Redis本身没有强的模式,在使用中,所有人都可以随意地设置redis的存储,那么我们要如何才能高效地使用redis呢?有一些问题就需要在存储的设计时要注意了。
Key的命名要简短,且有意义。Key在redis中也是要占用空间的,并且内存是很宝贵的,所以要节约使用。当key名有意义,那么在程序的逻辑处理过程中,就有可能直接获得key名,从而直接去获取到相应的value了。
Value值不宜过大。当value在1k的时候,redis可以支持到10w/s左右,那当value的大小达到10k,那么redis就只能支持到1w/s左右了。可见value的大小对于redis的效率还是很有影响的。所以,每个key的value值要尽量精简,哪怕是冗余一些多余的key也不要制造一个超级大的key因为那样的话,还不如使用其他的存储来得实惠了。
返回的数据要尽量紧凑,小型。虽然redis没有对客户端做什么限制,但是他是预留了功能的,可以在一次请求超过了多久,或者是总数据量超过多少,还有就是规定时间内发送数据超过多少的情况下,就可以直接杀死链接,没有任何返回,也没有任何道理。所以要注意,只返回有用的东西。
对于list要活学活用。我们不能做KEYS,那么当我们又需要将某种类型的KEY进行计数的时候,我们就应该去使用list了。将一些相关的key都存放于一个list中,我们就可以轻松地使用LLEN来获取到list的长度,其效果可以抵消一部分KEYS的应用场景了。对于list也并不是万灵药,虽然在很多情况下,list可以消耗更少的资源来做到和key相同的效果,但是也要注意,list不适宜过长,要做到可控。
Set(集合)的运用,与list类似,就不多描述了,参见一下redis的命令列表吧。这也是一种非常有用的数据结构。
对于list和set还是要说两句,正因为有了这样的数据结构,我们得以用更小的代价管理更加庞大的key。
要用SETEX去设置key的过期时间。Redis本身就是一个缓存,只是一个缓存,在需要持久化的场景下,不要妄想能在redis中做的存储大量的值。所以redis中尽量存储一些不需要持久化的东西,并且如果关联到持久化的数据的话,最好能有缓存载入的脚本,能手工载入一些缓存数据,在出现整个redis集群完全崩溃的情况下可以减少crash到数据库的时间。
我们是单线程!又说到这个话题了,redis就是个单线程,我觉得也不太可能改造了。那么我们怎么来应对大量并发呢?
其实并不是没招,招有的是。
方法一,我们可以使用队列,将请求放入队列中,再取出处理,将大量的并发序列化,持续地,高效地在redis中处理。
方法二,读写分离。在有可能的情况下一定要具备读写分离功能。当序列化后依然无法响应大量的并发,那么我们就需要做读写分离了。这样只要在量上来时,多拉实例,并添加到负载均衡即可了。
要为分布式做好准备。现在本司在redis的分布式上选型是twemproxy,在分布式的情景下,很多操作会受到限制,所以,当可以预见到redis在将来会增长到需要做分布式的场景下,就需要注意了,在编码中就要有意去规避这些操作,以减少将来修改的成本。
如何去界定一个redis是否需要做成分布式,建议当redis的数据量超过15G时就需要更换为分布式,当redis的数据量达到8G,并且有增长的趋势时,就需要考虑分布式的方案了。
就本司当前情况来看,只有少量的一些应用会达到分布式的要求,其他的,因为历史原因,不适合马上切换为分布式。大量的应用还是处于读写分离即可支持的情况下,所以不一定上线,但一定要有读写分离的方案,或者是预案。
后续的一些展望
在后续的规划中,redis更加倾向于小型化,轻量化的部署。这里有两条路,一是集中化的分布式redis,虽然将数据打散了,这样解决了容量的问题,但是,但是!我们特么还是单线程!同时,集群化,也限制了一些特殊的操作,但是这些小技巧有的时候又是非常nice的。那么我们就提出了第二个方案,二级缓存。在持久化层上有几个集群,这些集群又可做读写分离,在这个大容量的缓存上每个服务,甚至是每个进程都对应一个自己的超级轻量化redis,不需要预加载,不怕数据丢失,随时可重启的这种,当然,可以做到读写分离也是极好的。每个关于缓存的请求,都会先去查询二级缓存中的redis(轻量化的那个),当不命中时,会去一级缓存(大容量的那个)中查询,如果命中,则将数据加载至二级缓存,返回结果。当一级缓存也不能命中时,就要去到持久化层获取实际的数据,并同时将数据加载到一级和二级缓存了。
二级缓存的模式下,又涉及到读写分离等问题,但那时,将是千万级别并发访问了,希望将来有一天能够看见。
一篇关于Redis的好文章的更多相关文章
- 一篇和Redis有关的锁和事务的文章
部分参考链接 Transaction StackExchange.Redis Transaction hashest 正文 Redis 是一种基于内存的单线程数据库.意味着所有的命令是一个接一个的执行 ...
- 《【面试突击】— Redis篇》--Redis都有哪些数据类型?分别在哪些场景下使用比较合适?
能坚持别人不能坚持的,才能拥有别人不能拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>--Redis都有哪些数据类型?分别在哪些场景下使用 ...
- 《【面试突击】— Redis篇》-- Redis的线程模型了解吗?为啥单线程效率还这么高?
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的线程模型了解吗?为啥单线程效率还这 ...
- 《【面试突击】— Redis篇》-- Redis的主从复制?哨兵机制?
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注左上角编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis的主从复制?哨兵机制? 在这个 ...
- 《【面试突击】— Redis篇》-- Redis哨兵原理及持久化机制
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>-- Redis哨兵原理及持久化机制 在这个系列里, ...
- 《【面试突击】— Redis篇》--Redis Cluster及缓存使用和架构设计的常见问题
能坚持别人不能坚持的,才能拥有别人未曾拥有的.关注编程大道公众号,让我们一同坚持心中所想,一起成长!! <[面试突击]— Redis篇>--Redis Cluster及缓存使用和架构设计的 ...
- 前两篇转载别人的精彩文章,自己也总结一下python split的用法吧!
前言:前两篇转载别人的精彩文章,自己也总结一下吧! 最近又开始用起py,是为什么呢? 自己要做一个文本相似度匹配程序,大致思路就是两个文档,一个是试题,一个是材料,我将试题按每题分割出来,再将每题的内 ...
- 一篇关于PHP性能的文章
一篇关于PHP性能的文章 昨晚清理浏览器收藏夹网址时,发现了http://www.phpbench.com/,想起来应该是2015年发现的一个比较性能的文章,我就点进去看了看,发现还是全英文耶,刚好最 ...
- 几篇关于RGBD语义分割文章的总结
最近在调研3D算法方面的工作,整理了几篇多视角学习的文章.还没调研完,先写个大概. 基于RGBD的语义分割的工作重点主要集中在如何将RGB信息和Depth信息融合,主要分为三类:省略. 目录 ...
随机推荐
- 打jar包
1.在文件夹中新建文件manifest.mf 2.在dos窗口中jar cvfm 名字.jar manifest.mf 所有的编译的类class,中间有空格 3.在dos窗口java -jar 名字 ...
- POJ-1189 钉子和小球(动态规划)
钉子和小球 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7452 Accepted: 2262 Description 有一个 ...
- Linux crontab下关于使用date命令和sudo命令的坑
想要在root 的crontab里面加一些任务计划,希望以www用户运行命令,并且将输出重定向到某处以当时时间命名的日志文件,大致如下 /usr/bin/sudo -u www /usr/local/ ...
- hyperledger
http://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html https://github.com/hyperledger/block ...
- LINUX常用命令大全归纳篇
su su命令是最基本的命令之一,常用于不同用户间切换. 例如,如果登录为 user1,要切换为user2,只要用如下命令: $su user2 然后系统提示输入user2口令,输入正确的口令之后就可 ...
- HTML5 Storage(永久存储)
localStorage.aa="aa"; //存储了一个key为aa并且value为aa的键值对: localStorage.setItem("bb", &q ...
- PyQt5标准对话框
很全的Qt的标准对话框,包含QInputDialog.QColorDialog.QFontDialog.QMessageBox.QOpenFileDialog... 全部是由官网的C++版本,转换成P ...
- 模仿linux内核定时器代码,用python语言实现定时器
大学无聊的时候看过linux内核的定时器,如今已经想不起来了,也不知道当时有没有看懂,如今想要模仿linux内核的定时器.用python写一个定时器,已经想不起来它的设计原理了.找了一篇blog,li ...
- 梯度下降法实现-python[转载]
转自:https://www.jianshu.com/p/c7e642877b0e 梯度下降法,思想及代码解读. import numpy as np # Size of the points dat ...
- [LeetCode] 121. Best Time to Buy and Sell Stock_Easy tag: Dynamic Programming
Say you have an array for which the ith element is the price of a given stock on day i. If you were ...