Redis性能优化——针对实习面试

目录

  • Redis性能优化
    • 什么是bigkey?
    • bigkey的危害?
    • 如何处理bigkey?
    • 什么是hotkey?
    • hotkey的危害?
    • 如何处理hotkey?
    • 如何处理大量key集中过期问题?
    • 什么是内存碎片?
    • 为什么会有Redis内存碎片?
    • 如何处理Redis内存碎片?

Redis性能优化

在这里插入图片描述

什么是bigkey?

在Redis中,所谓的"bigkey"指的是那些占用较大空间的键值对。这些键因为包含了大量的数据,可能会对Redis的性能和内存使用产生显著影响。具体来说,bigkey主要体现在两个方面:

  1. 字符串类型的bigkey:如果一个键对应的字符串类型的值过大,一般认为超过10KB就可以被视为bigkey
  2. 非字符串类型的bigkey:对于哈希(hash)、列表(list)、集合(set)、有序集合(zset)等非字符串类型的键,如果它们包含的元素数量超过了一定阈值(通常认为是5000个元素),也可以被认为是bigkey

bigkey的危害?

关于bigkey的危害,以下是最重要的几点,并伴有实例以增强说服力:

  1. 内存空间使用不均匀:在Redis集群中,bigkey可能导致各个节点的内存空间使用不均匀,这可能会引发节点间的负载不均衡,影响整体性能。
    例如:如果一个节点存储了一个非常大的列表或哈希表,它可能会占用该节点的大部分内存,导致其他节点的内存使用相对较低,从而影响集群的内存分配和数据均衡。

  2. 超时阻塞:由于Redis是单线程的,对bigkey的操作通常会比较耗时,这可能导致后续的请求被阻塞,增加Redis的响应时间,严重时可能导致服务不可用。
    例如:如果一个bigkey是一个包含数百万元素的列表,执行LRANGE操作可能会非常耗时,导致其他请求无法及时处理。

  3. 网络拥塞:每次获取bigkey会产生较大的网络流量。假设一个bigkey为1MB,每秒访问量为1000,那么每秒就会产生1000MB的流量,这对于普通的千兆网卡(128MB/s)的服务器来说是灾难性的。
    例如:如果服务器采用单机多实例的部署方式,一个bigkey可能会对其他实例造成影响,进一步加剧网络拥塞的问题。

  4. 过期删除时的阻塞:如果bigkey设置了过期时间,当过期后,如果没有使用Redis 4.0的过期异步删除功能,bigkey的删除操作可能会阻塞Redis,导致性能下降。
    例如:一个大型的有序集合(zset)如果设置了过期时间,其删除操作可能会占用大量CPU和内存资源,影响其他操作的执行。

如何处理bigkey?

在实际开发中,处理Redis中的bigkey是非常重要的,以下是最重要的几点处理方法,并伴有实例以增强说服力:

  1. 分割大key
    将一个bigkey拆分成多个小key,可以减少单个key对内存的占用和操作的耗时。
    例如,如果有一个包含上百万粉丝的社交类bigkey,可以通过用户ID进行哈希,将粉丝列表分散存储到多个keys中。

  2. 手动清理无效数据
    对于list和set类型的bigkey,可以定期清理无效数据
    例如,如果一个列表存储了大量不再需要的数据,可以逐步删除这些数据,以减少内存占用。

  3. 压缩对应的BigKey的value
    如果bigkey的value很大,可以通过序列化压缩的方法减小value的大小。如果压缩后仍然很大,则需要考虑拆分。

  4. 监控Redis中内存,带宽,增长率
    通过监控系统监控Redis中的内存占用大小网络带宽的占用大小,以及固定时间内的内存占用增长率,当超过设定的阈值时进行报警通知处理。

  5. 使用合适的数据结构
    选择合适的数据结构可以避免bigkey的产生。
    例如,使用HyperLogLog统计页面UV,使用Bitmap保存状态信息(0/1)。

  6. 开启lazy-free(惰性删除/延迟释放)
    Redis 4.0开始引入的lazy-free特性,指的是让Redis采用异步方式延迟释放key使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程。

  7. 避免使用全数据查询命令
    如果必须使用bigkey,那么操作时应该避开全数据查询的命令,如hgetall、lrange、smembers、zrange等,可以使用hscan、sscan、zscan代替进行遍历。

  8. 合理使用数据类型
    设计阶段就应该尽量避免bigkey,所以选择合适的数据类型尤为重要。
    例如,将多个字段存储在一个hash中,而不是分散在多个keys中。

以上方法可以配合使用,以确保Redis的性能和稳定性。在实际应用中,处理bigkey需要根据具体情况灵活选择策略。

什么是hotkey?

在Redis中,hotkey是指被频繁访问的键(key),这种情况通常出现在客户端频繁查询、读取或写入同一个key时。以下是hotkey的几个重要特点及其产生的原因:

什么是Hotkey

Hotkey即Redis实例中的热点数据,当客户端频繁访问同一个key时,该key被称为hotkey。

Hotkey的出现原因

  1. 高访问频率:某个key因为业务逻辑需要被频繁访问,例如电商平台中的热门商品信息。
  2. 业务活动:特定的营销活动或事件导致某些数据被集中访问,如秒杀活动的商品信息。
  3. 机器人或爬虫访问自动化脚本频繁访问特定key,如用户行为分析中的userId或ip。

实例

假设一个电商平台在进行“双11”大促,某个爆款商品的库存信息存储在Redis中。如果这个商品的SKU ID对应的key被频繁查询,那么这个key就成为了hotkey。这可能导致该实例的网络流量激增,影响其他key的访问,甚至可能导致数据库因为请求过多而压力过大,出现服务不稳定的情况。

hotkey的危害?

Hotkey在Redis中指的是被频繁访问的键,这种频繁的访问可能会对系统性能和稳定性造成影响。以下是hotkey最重要的几点危害:

  1. 资源竞争和性能瓶颈

    • 当一个key被频繁访问时,它会占用大量的CPU和内存资源,导致Redis服务器在处理这个key时出现性能瓶颈。这会降低Redis处理其他请求的能力,影响整体性能。
  2. 缓存击穿风险

    • 如果hotkey设置了过期时间并在到期时被清除,而此时有大量请求尝试访问这个key,这些请求将直接穿透缓存到达后端数据库,可能导致数据库压力骤增,甚至崩溃
  3. 主从同步延迟

    • 在主从复制的环境中,hotkey的频繁更新可能会导致主从同步延迟,因为从节点需要时间来复制主节点的数据变更。这可能会导致数据不一致的问题,尤其是在写入频繁的情况下。
  4. 数据倾斜

    • 在Redis集群环境中,hotkey可能导致数据倾斜,即某些节点因为hotkey的存在而承受更多的请求压力,而其他节点则相对较轻。这种不均衡的负载分布可能会影响集群的扩展性和容错能力
  5. 网络拥塞

    • 频繁访问hotkey可能会导致网络拥塞,尤其是在主从复制或集群节点间同步数据时。这不仅影响Redis内部的数据传输,也可能影响到其他服务的正常运行。
  6. 系统稳定性风险

    • hotkey的存在可能会成为系统的一个单点故障。如果处理hotkey的节点出现故障,可能会导致服务中断,影响整个系统的稳定性。

如何处理hotkey?

处理Redis中的hotkey是确保系统稳定性和性能的重要步骤。以下是最重要的几点处理方法,以及相应的详细说明和实例:

  1. 使用redis-cli --hotkeys命令定位Hotkey

    • 从Redis 4.0.3版本开始,Redis引入了hotkeys命令来帮助定位访问频率最高的键。这个命令可以实时提供热点键的信息,但它可能对性能产生影响,因此不推荐在生产环境频繁执行
  2. TCP抓包分析

    • 使用ELK提供的packetbeat抓包插件对Redis的TCP报文进行抓包与分析,可以做到对业务端无侵入性、对Redis实例本身性能无影响。
  3. 多级缓存策略

    • 对于定位到的Hotkey,可以灵活调整缓存策略,比如客户端本地+分布式缓存、全局缓存+局部缓存等,以减轻单个Redis实例的压力。
  4. 监控优化

    • 完善监控与告警,多维度分析Hotkey场景下机器的QPS、内存、网络等资源的使用情况。当达到策略阈值时,可以配合自动化运维增加扩容、调整缓存配置、slot迁移等策略。
  5. 根据业务拆分子key

    • 对于数量较少且可以对key或value自身进行拆分的情况,可以将Hotkey尽量分散落到不同的实例上,减轻单个实例的压力。
  6. 缓存策略与TTL优化

    • 合理配置TTL,并使用适当的缓存策略,如LRU(Least Recently Used)或LFU(Least Frequently Used),以便自动淘汰冷数据并保留热点数据,避免Hotkey过期导致频繁的缓存击穿的情况。

实例
假设一个电商平台在“双11”大促期间,某个爆款商品的库存信息存储在Redis中,该key被频繁查询,成为hotkey。可以采取以下措施:

  • 使用redis-cli --hotkeys命令来识别这个hotkey。
  • 实施多级缓存策略,将该商品的库存信息同时存储在本地缓存和Redis中,减少对Redis的直接访问。
  • 监控优化,通过监控系统实时监控该key的访问频率和相关资源使用情况,一旦检测到异常,自动执行扩容或迁移操作。
  • 拆分子key,如果该商品的库存信息可以拆分,比如按照颜色或尺码,可以将原始key拆分为多个子key,分散访问压力。
  • 缓存策略与TTL优化,为该key设置一个合理的过期时间,并采用LRU或LFU策略,确保热点数据始终被缓存,同时淘汰访问频率低的数据。

通过这些方法,可以有效地处理Redis中的hotkey问题,保证系统的稳定性和响应速度。

如何处理大量key集中过期问题?

处理大量key集中过期的问题是Redis性能优化中的一个重要方面,以下是最重要的几点处理方法:

  1. 设置随机过期时间

    • 说明:为了避免大量key在同一时间过期,可以为key设置随机的过期时间。这样可以有效分散过期key的处理压力,减少Redis在某个时间点的负载。
    • 实例:假设有一个电商平台的优惠券系统,优惠券通常在特定时间过期。如果所有优惠券都设置为午夜12点过期,那么可能会导致Redis在午夜时分承受巨大压力。通过为每个优惠券设置一个随机的过期时间,比如在午夜前后的几分钟内,可以有效地分散过期key的处理压力。
  2. 开启lazy-free(惰性删除/延迟释放)

    • 说明:Redis 4.0引入了lazy-free特性,允许Redis以异步方式延迟释放key使用的内存,将该操作交给单独的子线程处理,避免阻塞主线程。
    • 实例:在一个高流量的新闻网站中,每篇文章的阅读次数存储在Redis中,并设置了一个较短的过期时间。如果大量文章在同一时间过期,开启lazy-free可以避免主线程被过期key的处理阻塞,从而保持Redis的响应速度。
  3. 使用多级缓存策略

    • 说明:通过在客户端本地缓存和分布式缓存之间灵活调整,可以减轻单个Redis实例的压力。
    • 实例:在一个大型社交网络中,用户的会话信息存储在Redis中。通过在用户的手机应用中实现本地缓存,并结合分布式缓存,可以减少对Redis的直接访问,从而降低单个key的过期处理压力。
  4. 监控优化和自动化运维

    • 说明:对Redis实例所在机器完善监控与告警,多维度分析机器的QPS、内存、网络等资源的使用情况。当达到策略阈值时,可以配合自动化运维进行扩容、调整缓存配置、slot迁移等策略。
    • 实例:在一个电商平台中,可以监控Redis实例的内存使用情况和请求量。当检测到某个实例的内存使用接近上限或者请求量激增时,自动触发扩容操作或者迁移部分数据到其他实例,以保持系统的稳定性和性能。
  5. 根据业务拆分子key

    • 说明:适用于key的数量较少且可以对key或value自身进行拆分的情况,使hotkey尽量分散落到不同的实例上。
    • 实例:在一个视频平台上,每个视频的观看次数存储在Redis中。如果某个视频非常热门,可以将其观看次数拆分到多个key中,比如按照日期或者观看来源拆分,以减少单个key的过期处理压力。

什么是内存碎片?

内存碎片(Memory Fragmentation)是指在计算机系统中,由于内存分配和释放不连续,导致内存中存在许多小的、不连续的空闲区域,这些区域太小而无法被有效利用,但总体上它们加起来可能占据了相当一部分的内存空间。内存碎片主要分为两种类型:

  1. 内部碎片(Internal Fragmentation)

    • 这种碎片发生在内存块内部,当分配的内存块比所需的稍大时,多余的部分就形成了内部碎片。例如,一个程序申请了128KB的内存,但实际只需要120KB,那么剩下的8KB就成为了内部碎片。
  2. 外部碎片(External Fragmentation)

    • 这种碎片发生在内存块之间,当内存中的空闲区域被分割成多个小的、不连续的块时,这些小的空闲块太小而无法满足新的内存申请请求,即使总的空闲内存足够大,也会导致无法分配内存的情况,这就是外部碎片。

内存碎片的问题在于,它降低了内存的有效利用率,可能导致系统虽然显示有足够的空闲内存,但仍然无法分配新的内存请求,最终可能导致内存耗尽的情况。在操作系统和内存管理中,内存碎片是一个需要被管理和优化的问题。

在Redis这样的内存数据库中,内存碎片也是一个需要关注的问题,因为Redis使用内存来存储数据,如果存在大量的内存碎片,可能会导致内存使用效率低下,影响性能。Redis通过使用不同的数据结构和内存分配策略来尽量减少内存碎片的影响。

为什么会有Redis内存碎片?

Redis内存碎片的产生主要有以下几个原因:

  1. 数据类型差异与分配策略

    • Redis支持多种数据类型,每种数据类型的内部实现和内存分配策略不同,导致内存分配与释放过程中可能出现不连续、不规则的空闲空间。例如,当删除一个大键值对后,原占用的空间可能无法被较小的新数据完全填充,形成内部碎片。
  2. 动态调整数据大小

    • Redis中某些数据类型(如字符串、哈希表)允许动态调整大小。当数据增长超过原有分配空间时,Redis会重新分配更大的内存块,并将旧数据复制到新空间,释放旧空间。若新分配的空间远大于实际所需,或者频繁发生此类操作,会加剧内存碎片的产生。
  3. 过期键清理与主动淘汰

    • Redis支持设置键的过期时间。当键过期后,其占用的内存空间会被释放,形成空洞。此外,当Redis遇到内存不足的情况,会启动主动淘汰策略(如LRU、LFU),移除部分键值对以释放内存。这些操作可能导致内存碎片的产生。
  4. 内存分配策略

    • 不同的内存分配策略对内存碎片的影响不同。Redis默认使用jemalloc作为内存分配器,jemalloc在处理大规模内存分配时,可能会导致碎片的积累。
  5. 频繁的键值对操作

    • Redis主要通过mallocfree函数来分配和释放内存。当Redis中的数据频繁更新或删除时,内存分配和释放操作频繁进行,容易导致内存碎片的产生。
  6. 不同数据结构的混用

    • Redis支持多种数据结构,这些数据结构在内存中的分布方式不同,混用这些数据结构可能导致内存分配的不连续性,从而产生碎片。

如何处理Redis内存碎片?

处理Redis内存碎片可以采取以下几种方法:

  1. 调整jemalloc参数

    • Redis默认使用jemalloc作为内存分配器,通过调整jemalloc的参数可以优化内存分配策略,减少内存碎片。例如,可以调整垃圾回收频率和碎片合并策略等参数。
  2. 触发手动内存整理

    • 通过执行MEMORY PURGE命令,可以主动清理未使用的内存,减少内存碎片
  3. 重启Redis实例

    • 重启Redis实例是最简单有效的方式之一。重启过程中,Redis会将内存中的数据重新加载到新的内存块中,从而减少内存碎片。
  4. 数据迁移

    • 通过主从复制或者集群分片的方式,将数据迁移到新的实例中。新的实例会重新分配内存,从而减少碎片。
  5. 定期整理大对象

    • 对于大对象的数据,可以考虑定期进行整理。例如,可以通过分批次删除和重新插入的方式,减少内存碎片的产生。
  6. 优化数据结构

    • 了解并利用Redis各种数据类型及编码方式的特点,可以减少内存碎片的产生。例如,使用整数集合(IntSet)代替集合(Set)存储整数值,使用ziplist编码的哈希表和列表存储小数据。
  7. 升级到Redis 6.0及以上版本

    • Redis 6.0及以上版本提供了更多的内存管理功能和优化,有助于减少内存碎片。
  8. 开启active-defrag特性

    • Redis 4.0-RC3版本开始引入了active-defrag特性,可以在不重启的情况下,自动进行碎片清理。通过设置config set activedefrag yes来开启此特性。需要注意的是,自动清理内存碎片的功能需要Redis的内存分配器是jemalloc时才能启用。
  9. 合理设置数据过期策略

    • 使用EXPIRE命令为键设置过期时间,或者使用Redis的过期策略,如LRU(Least Recently Used)淘汰策略、LFU(Least Frequently Used)淘汰策略等,定期清理过期或不再使用的数据。

通过上述方法,可以有效地处理Redis中的内存碎片问题,保持系统的稳定性和性能。

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

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

相关文章

小白进!QMK 键盘新手入门指南

经常玩键盘的伙伴应该都知道,现在的键盘市场可谓是百花齐放,已经不是之前的单一功能产品化时代。我们可以看到很多诸如:机械轴键盘、磁轴键盘、光轴键盘、电感轴键盘,以及可能会上市的光磁轴键盘,更有支持屏幕的、带旋…

分布式事务seata基于docker安装和项目集成seata

目录 本地事务 根据隔离性的等级会导致不同的问题 有四种隔离等级 分布式事务 现在有一个场景: 结果: CAP定理 矛盾 总结: es集群使用的是cp: BASE理论 解决分布式事务的思路 Seata Seata的架构 docker安装seata 1.拉取seat…

【Qt实现虚拟键盘】

Qt实现虚拟键盘 🌟项目分析🌟实现方式🌟开发流程 🌟项目分析 需求:为Linux环境下提供可便捷使用的虚拟键盘OS环境:Windows 7/11、CentOS 7开发语言:Qt/C IDE:QtCreator 、Qt5.14.2功…

react中如何在一张图片上加一个灰色蒙层,并添加事件?

最终效果: 实现原理: 移动到图片上的时候,给img加一个伪类 !!此时就要地方要注意了,因为img标签是闭合的标签,无法直接添加 伪类(::after),所以 我是在img外…

电子应用产品设计方案-11:全自动智能全屋智能系统设计方案

一、设计目标 打造便捷、舒适、安全且节能的全屋智能环境。 二、系统组成 1. 智能灯光系统 - 在客厅、卧室、厨房、卫生间等各处安装智能灯具,可通过手机 APP、语音控制实现开关、调光调色。如客厅设置多种场景模式,如“观影模式”(灯光…

服务端高并发分布式结构进阶之路

序言 在技术求知的旅途中,鉴于多数读者缺乏在中大型系统实践中的亲身体验,难以从宏观角度把握某些概念,因此,本文特选取“电子商务应用”作为实例,详细阐述从百级至千万级并发场景下服务端架构的逐步演变历程。同时&am…

WebRTC视频 02 - 视频采集类 VideoCaptureModule

WebRTC视频 01 - 视频采集整体架构 WebRTC视频 02 - 视频采集类 VideoCaptureModule(本文) WebRTC视频 03 - 视频采集类 VideoCaptureDS 上篇 WebRTC视频 04 - 视频采集类 VideoCaptureDS 中篇 WebRTC视频 05 - 视频采集类 VideoCaptureDS 下篇 一、前言…

POI实现根据PPTX模板渲染PPT

目录 1、前言 2、了解pptx文件结构 3、POI组件 3.1、引入依赖 3.2、常见的类 3.3、实现原理 3.4、关键代码片段 3.4.1、获取ppt实例 3.4.2、获取每页幻灯片 3.4.3、循环遍历幻灯片处理 3.4.3.1、文本 3.4.3.2、饼图 3.4.3.3、柱状图 3.4.3.4、表格 3.4.3.5、本地…

sqli-labs靶场17-20关(每日四关)持续更新!!!

Less-17 打开靶场,发现页面比之前多了一行字 翻译过来就是,密码重置,大家肯定会想到,自己平时在日常生活中怎么密码重置,肯定是输入自己的用户名,输入旧密码,输入新密码就可以了,但…

node.js下载安装步骤整理

>> 进入node.js下载页面下载 | Node.js 中文网 >>点击 全部安装包 >>删除网址node后面部分,只保留如图所示部分,回车 >>点击进入v11.0.0/版本 >>点击下载node-v11.0.0-win-x64.zip(电脑是windows 64位操作系统适用) >…

ThinkServer SR658H V2服务器BMC做raid与装系统

目录 前提准备 一. 给磁盘做raid 二. 安装系统 前提准备 磁盘和系统BMC地址都已经准备好,可正常使用。 例: 设备BMC地址:10.99.240.196 一. 给磁盘做raid 要求: 1. 将两个894G的磁盘做成raid1 2. 将两块14902G的磁盘各自做…

SpringBoot配置类

在Spring Boot中,配置类是一种特殊的类,用于定义和配置Spring应用程序的各种组件、服务和属性。这些配置类通常使用Java注解来声明,并且可以通过Spring的依赖注入机制来管理和使用。 Spring 容器初始化时会加载被Component、Service、Reposi…

SpringBoot教程(二十五) | SpringBoot配置多个数据源

SpringBoot教程(二十五) | SpringBoot配置多个数据源 前言方式一:使用dynamic-datasource-spring-boot-starter引入maven依赖配置数据源动态切换数据源实战 方式二:使用AbstractRoutingDataSource1. 创建数据源枚举类2. 创建数据源…

ZooKeeper单机、集群模式搭建教程

单点配置 ZooKeeper在启动的时候,默认会读取/conf/zoo.cfg配置文件,该文件缺失会报错。因此,我们需要在将容器/conf/挂载出来,在制定的目录下,添加zoo.cfg文件。 zoo.cfg logback.xml 配置文件的信息可以从二进制包…

【大数据学习 | HBASE高级】hbase-phoenix 与二次索引应用

1. hbase-phoenix的应用 1.1 概述: 上面我们学会了hbase的操作和原理,以及外部集成的mr的计算方式,但是我们在使用hbase的时候,有的时候我们要直接操作hbase做部分数据的查询和插入,这种原生的方式操作在工作过程中还…

拆解测试显示Mac Mini (2024)固态硬盘并未锁定 互换硬盘后仍可使用

此前已经有维修达人尝试将 Mac Mini (2024) 固态硬盘上的 NAND 闪存拆下并替换实现扩容,例如可以从 256GB 扩容到 2TB。虽然接口类似于 NVMe M.2 SSD 但直接安装普通硬盘是无效的,苹果仍然通过某种机制检测硬盘是否能够兼容。 不过知名拆解网站 iFixit 的…

主界面获取个人信息客户端方

主界面获取个人信息客户端方 前言 上一集我们完成了websocket身份验证的内容,那么这一集开始我们将要配合MockServer来完成主界面获取个人信息的内容。 需求分析 我们这边是完成客户端那方的内容,当客户端登录成功之后,我们就要从服务器获…

Spring整合Redis

前言 在Spring项目中整合Redis,能显著提升数据缓存、分布式锁、会话管理等操作的效率。Jedis作为轻量级的Java Redis客户端,搭配Spring Data Redis模块,能够简化Redis的连接和数据操作,实现更高性能的读写与灵活的缓存管理。本文…

爬虫——Requests库的使用

在爬虫开发中,HTTP请求是与服务器进行交互的关键操作。通过发送HTTP请求,爬虫可以获取目标网页或接口的数据,而有效地处理请求和响应是爬虫能够高效且稳定运行的基础。Requests库作为Python中最常用的HTTP请求库,因其简洁、易用和…

LinkedHashMap实现LRU

LRU 环境:JDK11 最近接触LRU(Least Recently Used),即最近最少使用,也称淘汰算法,在JDK中LinkedHashMap有相关实现 LRU的LinkedHashMap实现 LinkedHashMap继承HashMap。所以内存的存储结构和HashMap一样,但是LinkedH…