校园门户网站建设实施方案,中企动力网站建设方案,网络营销方案策划,wordpress模板打开慢提示#xff1a;文章写完后#xff0c;目录可以自动生成#xff0c;如何生成可参考右边的帮助文档 文章目录 BigKey1.什么是bigkey2.bigkey的危害3.发现bigkeyscan 4.解决bigkey 什么是热点Key#xff1f;该如何解决1. 产生原因和危害原因危害 2.发现热点key预估发现客户端… 提示文章写完后目录可以自动生成如何生成可参考右边的帮助文档 文章目录 BigKey1.什么是bigkey2.bigkey的危害3.发现bigkeyscan 4.解决bigkey 什么是热点Key该如何解决1. 产生原因和危害原因危害 2.发现热点key预估发现客户端发现Redis发现monitor命令hotkeys 抓取TCP包发现 3. 解决热点key使用二级缓存key分散 BigKey
1.什么是bigkey
bigkey是指key对应的value所占的内存空间比较大例如一个字符串类型的value可以最大存到512MB一个列表类型的value最多可以存储23-1个元素。
如果按照数据结构来细分的话一般分为字符串类型bigkey和非字符串类型bigkey。
字符串类型体现在单个value值很大一般认为超过10KB就是bigkey但这个值和具体的OPS相关。
非字符串类型哈希、列表、集合、有序集合,体现在元素个数过多。
bigkey无论是空间复杂度和时间复杂度都不太友好下面我们将介绍它的危害。
2.bigkey的危害
bigkey的危害体现在三个方面: 内存空间不均匀.(平衡):例如在Redis Cluster中bigkey 会造成节点的内存空间使用不均匀。 超时阻塞:由于Redis单线程的特性操作bigkey比较耗时也就意味着阻塞Redis可能性增大。 网络拥塞:每次获取bigkey产生的网络流量较大
假设一个bigkey为1MB每秒访问量为1000那么每秒产生1000MB 的流量,对于普通的千兆网卡(按照字节算是128MB/s)的服务器来说简直是灭顶之灾而且一般服务器会采用单机多实例的方式来部署,也就是说一个bigkey可能会对其他实例造成影响,其后果不堪设想。
bigkey的存在并不是完全致命的
如果这个bigkey存在但是几乎不被访问,那么只有内存空间不均匀的问题存在,相对于另外两个问题没有那么重要紧急,但是如果bigkey是一个热点key(频繁访问)那么其带来的危害不可想象,所以在实际开发和运维时一定要密切关注bigkey的存在。
3.发现bigkey
redis-cli --bigkeys可以命令统计bigkey的分布。 但是在生产环境中开发和运维人员更希望自己可以定义bigkey的大小而且更希望找到真正的bigkey都有哪些,这样才可以去定位、解决、优化问题。
判断一个key是否为bigkey只需要执行debug object key查看serializedlength属性即可它表示 key对应的value序列化之后的字节数。 如果是要遍历多个则尽量不要使用keys的命令可以使用scan的命令来减少压力。
scan
Redis 从2.8版本后提供了一个新的命令scan它能有效的解决keys命令存在的问题。和keys命令执行时会遍历所有键不同,scan采用渐进式遍历的方式来解决 keys命令可能带来的阻塞问题但是要真正实现keys的功能,需要执行多次scan。可以想象成只扫描一个字典中的一部分键直到将字典中的所有键遍历完毕。scan的使用方法如下:
scan cursor [match pattern] [count number]cursor 是必需参数实际上cursor是一个游标第一次遍历从0开始每次scan遍历完都会返回当前游标的值,直到游标值为0,表示遍历结束。
Match pattern 是可选参数,它的作用的是做模式的匹配,这点和keys的模式匹配很像。
Count number 是可选参数,它的作用是表明每次要遍历的键个数,默认值是10,此参数可以适当增大。 可以看到第一次执行scan 0返回结果分为两个部分:
第一个部分9就是下次scan需要的cursor
第二个部分是10个键。接下来继续
直到得到结果cursor变为0说明所有的键已经被遍历过了。
除了scan 以外Redis提供了面向哈希类型、集合类型、有序集合的扫描遍历命令解决诸如hgetall、smembers、zrange可能产生的阻塞问题对应的命令分别是hscan、sscan、zscan它们的用法和scan基本类似请自行参考Redis官网。 渐进式遍历可以有效的解决keys命令可能产生的阻塞问题但是scan并非完美无瑕如果在scan 的过程中如果有键的变化(增加、删除、修改)那么遍历效果可能会碰到如下问题:新增的键可能没有遍历到遍历出了重复的键等情况也就是说scan并不能保证完整的遍历出来所有的键这些是我们在开发时需要考虑的。
如果键值个数比较多scan debug object会比较慢可以利用Pipeline机制完成。对于元素个数较多的数据结构debug object执行速度比较慢存在阻塞Redis的可能所以如果有从节点,可以考虑在从节点上执行。
4.解决bigkey 主要思路为拆分 对 big key 存储的数据 big value进行拆分变成value1value2… valueN等等。
例如big value 是个大json 通过 mset 的方式将这个 key的内容打散到各个实例中或者一个hash每个field代表一个具体属性通过hget、hmget获取部分valuehset、hmset来更新部分属性。例如big value 是个大list可以拆成将list拆成。 list_1 list_2, list3, …listN
其他数据类型同理。
什么是热点Key该如何解决 在Redis中访问频率高的key称为热点key。 1. 产生原因和危害
原因
热点问题产生的原因大致有以下两种
用户消费的数据远大于生产的数据热卖商品、热点新闻、热点评论、明星直播。
在日常工作生活中一些突发的事件例如双十一期间某些热门商品的降价促销当这其中的某一件商品被数万次点击浏览或者购买时会形成一个较大的需求量这种情况下就会造成热点问题。同理被大量刊发、浏览的热点新闻、热点评论、明星直播等这些典型的读多写少的场景也会产生热点问题。
请求分片集中超过单Server的性能极限。在服务端读数据进行访问时往往会对数据进行分片切分此过程中会在某一主机Server上对相应的Key进行访问当访问超过Server极限时就会导致热点Key问题的产生。
危害
1、流量集中达到物理网卡上限。
2、请求过多缓存分片服务被打垮。
3、DB击穿引起业务雪崩。
2.发现热点key
预估发现
针对业务提前预估出访问频繁的热点key例如秒杀商品业务中秒杀的商品都是热点key。
当然并非所有的业务都容易预估出热点key可能出现漏掉或者预估错误的情况。
客户端发现
客户端其实是距离key最近的地方因为Redis命令就是从客户端发出的以Jedis为例可以在核心命令入口使用这个Google Guava中的AtomicLongMap进行记录如下所示。
使用客户端进行热点key的统计非常容易实现但是同时问题也非常多
(1) 无法预知key的个数存在内存泄露的危险。
(2) 对于客户端代码有侵入各个语言的客户端都需要维护此逻辑维护成本较高。
(3) 规模化汇总实现比较复杂。
Redis发现
monitor命令
monitor命令可以监控到Redis执行的所有命令利用monitor的结果就可以统计出一段时间内的热点key排行榜命令排行榜客户端分布等数据。 Facebook开源的redis-faina正是利用上述原理使用Python语言实现的例如下面获取最近10万条命令的热点key、热点命令、耗时分布等数据。为了减少网络开销以及加快输出缓冲区的消费速度monitor尽可能在本机执行。
此种方法会有两个问题
1、monitor命令在高并发条件下内存暴增同时会影响Redis的性能所以此种方法适合在短时间内使用。
2、只能统计一个Redis节点的热点key对于Redis集群需要进行汇总统计。
可以参考的框架Facebook开源的redis-faina正是利用上述原理使用Python语言实现的
hotkeys
Redis在4.0.3中为redis-cli提供了–hotkeys用于找到热点key。 如果有错误需要先把内存逐出策略设置为allkeys-lfu或者volatile-lfu否则会返回错误。 但是如果键值较多执行较慢和热点的概念的有点背道而驰同时热度定义的不够准确。
抓取TCP包发现
Redis客户端使用TCP协议与服务端进行交互通信协议采用的是RESP。如果站在机器的角度可以通过对机器上所有Redis端口的TCP数据包进行抓取完成热点key的统计
此种方法对于Redis客户端和服务端来说毫无侵入是比较完美的方案但是依然存在3个问题
(1) 需要一定的开发成本
(2) 对于高流量的机器抓包对机器网络可能会有干扰同时抓包时候会有丢包的可能性。
(3) 维护成本过高。
对于成本问题有一些开源方案实现了该功能例如ELK(ElasticSearch Logstash Kibana)体系下的packetbeat[2] 插件可以实现对Redis、MySQL等众多主流服务的数据包抓取、分析、报表展示
3. 解决热点key
发现热点key之后需要对热点key进行处理。
使用二级缓存
可以使用guava-cache或hcache发现热点key之后将这些热点key加载到JVM中作为本地缓存。访问这些key时直接从本地缓存获取即可不会直接访问到redis层了有效的保护了缓存服务器。
key分散
将热点key分散为多个子key然后存储到缓存集群的不同机器上这些子key对应的value都和热点key是一样的。当通过热点key去查询数据时通过某种hash算法随机选择一个子key然后再去访问缓存机器将热点分散到了多个子key上。