- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
Redis系列1:深刻理解高性能Redis的本质 Redis系列2:数据持久化提高可用性 Redis系列3:高可用之主从架构 Redis系列4:高可用之Sentinel(哨兵模式) Redis系列5:深入分析Cluster 集群模式 追求性能极致:Redis6.0的多线程模型 追求性能极致:客户端缓存带来的革命 Redis系列8:Bitmap实现亿万级数据计算 Redis系列9:Geo 类型赋能亿级地图位置计算 Redis系列10:HyperLogLog实现海量数据基数统计 Redis系列11:内存淘汰策略 Redis系列12:Redis 的事务机制 Redis系列13:分布式锁实现 Redis系列14:使用List实现消息队列 Redis系列15:使用Stream实现消息队列 Redis系列16:聊聊布隆过滤器(原理篇) Redis系列17:聊聊布隆过滤器(实践篇) Redis系列18:过期数据的删除策略 Redis系列19:LRU内存淘汰算法分析 Redis系列20:LFU内存淘汰算法分析 Redis系列21:缓存与数据库的数据一致性讨论 Redis系列22:Redis 的Pub/Sub能力 。
Redis是我们在业务开发中很重要的一个辅助,能够极大提高我们系统的运行效率,为后端的存储服务减少压力,提升用户使用体验。 但是作为一个辅助提升速度的组件,如果自己存在请求延迟的情况,那将是一个巨大的灾难,可能引起整条业务链路的雪崩。 在我以往的博客里面,也有过相应的案例,比如 《 架构与思维:一次缓存雪崩的灾难复盘 》。 但在实际业务场景中,可能有更加复杂的原因导致Redis访问效率变慢,下面我们详细来分析下.
在之前的章节中,我们根据官网的资料有过这样的结论: 在较高的配置基准下(比如 8C 16G +),在连接数为0~10000的时候,最高QPS可达到120000。Redis以超过60000个连接为基准,仍然能够在这些条件下维持50000个q/s,体现了超高的性能。下图中横轴是连接数,纵轴是QPS.
可见,Redis的性能和流量可抗性是极其高的,从客户端request发出到接受到response,这个处理过程时间是极短的,一般是微秒级别。 而对比Redis出现性能瓶颈的时候,就会有比较异常的表现,如达到几秒甚至几十秒,这时候我们就可以认定 Redis 性能变差了,需要去优化.
感知到 Redis的变慢了,接下来我们要做的就是验证和确认,这样才能有针对性的进行优化。 我们通过以下方法进行验证和分析.
redis-cli 提供了一个指令选项 --intrinsic-latency ,用于监测和统计某个时间段内Redis的最大延迟。这个选项可以用来评估Redis本身的性能,并且可以作为Redis的基准性能。 使用--intrinsic-latency选项需要指定时长,例如120秒。在指定的时间段内,redis-cli会记录每个秒级的最大延迟。这个最大延迟可以反映出Redis本身的性能,不受网络或其他外部因素的影响。 你可以通过以下命令使用--intrinsic-latency选项:
redis-cli --intrinsic-latency 120
执行该命令后,redis-cli会输出在120秒内的最大延迟统计信息。 需要注意的是,--intrinsic-latency选项从Redis的2.8.7版本开始支持。如果你使用的是较早的版本,可能无法使用该选项.
redis-cli --intrinsic-latency 120
Max latency so far: 5 microseconds.
Max latency so far: 14 microseconds.
Max latency so far: 33 microseconds.
Max latency so far: 52 microseconds.
Max latency so far: 70 microseconds.
Max latency so far: 130 microseconds.
Max latency so far: 272 microseconds.
Max latency so far: 879 microseconds.
Max latency so far: 1079 microseconds.
Max latency so far: 1665 microseconds.
Max latency so far: 1665 microseconds.
可以看到,当前运行的最大延迟是 1665 微秒,所以基线延迟的性能是 1665 (约 1.6 毫秒)微秒。 可以在终端上连接Redis的服务端进行测试,避免客户端测试因为网络的影响导致差异较大。 可以通过 -h host -p port 来连接到服务端.
redis-cli --latency -h `host` -p `port`
在算法设计中,最优的时间复杂度是O(1) 和 O(log N)。 一样的 ,Redis官方也尽量自身的操作指令尽量的高效,尽量节省时间复杂度。但是涉及到集合操作、全量的复杂度一般为O(N), 。
排查是否使用了慢指令,可以用如下几种方式:
如果只是简单判断是否使用了慢速查询,还可以使用命令 top、htop、prstat 等检查 Redis 主进程的 CPU 消耗即可 。
在 Redis 中,slowlog 是一个用于查询和记录执行时间较长的命令的命令。它可以帮助你找出哪些命令的执行时间超过了设定的阈值,并且将这些命令记录下来,以便后续分析和优化。 默认情况下命令执行时间超过 10ms 就会被记录到日志,这个只记录执行时间,摒弃了 io 往返或者网络延迟引起的响应慢部分。 如果你想修改慢查询的时间阈值,自定义慢查询的耗时标准,可以执行如下命令:
redis-cli CONFIG SET slowlog-log-slower-than 3330
这边为什么使用 3330 ,是因为我们采用上面基线延迟测试值的double.
slowlog 命令的基本语法如下:
slowlog get [count]
其中,count 是一个可选参数,表示要返回的 slow log 的数量。如果不指定 count,则默认返回最近的 slow log。 当执行 slowlog get 命令时,Redis 会返回最近的一些 slow log,每个 slow log 包含以下信息:
# 举例:读取最近2个慢查询
127.0.0.1:6381> SLOWLOG get 2
1) 1) (integer) 17
2) (integer) 1693641198
3) (integer) 5427
4) 1) "hgetall"
2) "all.uer_info"
1) 1) (integer) 18
2) (integer) 1693641217
3) (string) "GET"
4) (integer) 3771
第一个 HGET 命令,共 4 个字段:
根据我们之前的知识,Redis 的数据读写这个主操作是由单线程执行,如果被影响,导致阻塞,那么性能就会大大降低。 所以,如何避免主线程阻塞,是我们解决Redis慢执行的一个关键因素。以下从一个方向 。
互联网时代,客户端访问Redis服务端的时候很可能回到网络延迟较高,这样,客户端连接并请求的的效率就会变低。 如果是多个数据中心或者多网络分区的场景(两地三中心、异地多活),这种情况就更明显,毕竟数据在网络中传输都是视距离时延的。 通过 TCP/IP 连接或 Unix 域连接连接到 Redis,1 Gbit/s 的网络延迟大约为 200 us。 从下面这个图看到往返时间RTT(Round trip time),执行过程为:
我们上面与分析过慢指令,在算法设计中,最优的时间复杂度是O(1) 和 O(log N)。所以当我们确认了有慢查询指令。可以通过以下两种方式解决:
我们在数据持久化的篇章中,说过数据持久化的一些办法,包括RDB内存快照和AOF日志。使用的不合理,也会照成Redis的性能大打折扣。 生成 RDB 快照(参考这篇 《 Redis系列2:数据持久化提高可用性 》),Redis 必须 fork 后台进程, 做了fork操作之后,实际是拆分了执行出去,因为在主线程中执行,所以会导致性能降低,操作延迟。 在Redis 中可以使用操作系统的 COW(Copy On Write,多进程写时复制技术) 来快速持久化,减少内存占用。 Redis在执行 bgsave 时,涉及到内存和磁盘的分配和复制,并且从库加载 RDB 期间无法提供读写服务,为了保障高效率, 主库的数据量大小尽量控制在 2~4G 左右,超过4G,会让从库加载效率变慢,从而影响业务操作.
Linux 2.6.38 版本之后开始支持内存大页,最大可以支持2MB的内存页分配,而之前的常规页是按照4KB来分配的。 这样的话,会导致Redis本身的一些持久化操作的问题,(参考这篇 《 Redis系列2:数据持久化提高可用性 》).
可以使用指令来disable Linux 内存大页:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
Swap是操作系统中的一种虚拟内存技术,用于在物理内存不足时将一部分数据从物理内存中移动到硬盘上,以释放物理内存空间,避免系统因为内存不够而导致的 oom 情况。Swap操作包括“换出”(swap out)和“换入”(swap in)两个过程.
Swap操作可以帮助操作系统在物理内存不足时继续运行程序,但是过度的swap操作可能会导致系统性能下降,因为硬盘访问速度比物理内存慢得多。因此,合理配置和管理swap空间对于系统性能优化非常重要。 通常建议将swap空间设置为物理内存的1.5到2倍,并且应该避免在swap空间中频繁进行大量的读写操作.
既然swap的操作引发是由于内存空间不够导致的操作,那看看我们的Redis里面有哪些操作会引起这类行为:
# 获取Redis 实例的进程ID(pid):
$ redis-cli info | grep process_id
process_id:12893
# 根据进程进入 /proc 文件系统目录:
cd /proc/12893
# 打开 smaps 的文件,查找所有文件中所有的 swap 操作:
# 这边可以看到,当使用内存达到810554 kb 时,swap内存达到37kb。
$ cat smaps | egrep '^(Swap|Size)'
Size: 241 kB
Swap: 0 kB
Size: 172 kB
Swap: 0 kB
Size: 810554 kB
Swap: 37 kB
如果 Swap 是 0 kb,或者小量的kb,应该都是正常的。但当出现百 M,甚至 GB 级别的 swap 大小时,内存就明显吃紧了,大概率会导致线上请求变慢。 可以用如下办法进行解决:
为了保证数据可靠性,Redis 使用 AOF 和 RDB 快照实现快速恢复和持久化。 (参考这篇 《 Redis系列2:数据持久化提高可用性 》) 。
AOF(Append-Only File)作为Redis用于缓存持久化的一种方式,当你选择 "always" 作为 AOF 的写回策略时,这意味着每一个写操作都会被立即同步到磁盘中。 虽然这种策略可以最大限度地保证数据的安全性,但是它对性能的影响也是最大的,因为每次写操作都需要等待磁盘 I/O 完成。如果你的应用可以接受一点点数据丢失的风险,或者你的应用主要是读操作,你可能会想要调整 AOF 的写回策略以提高性能.
以下是几种可能的解决方案:
注意,调整持久化策略或使用缓存都可能会增加数据丢失的风险,因此你需要根据你的应用需求和风险承受能力来选择合适的策略.
参考这篇文章《 Redis系列18:过期数据的删除策略 》,我们有详细的描述 Redis 有两种方式淘汰过期数据:
定时任务的发起的频率由redis.conf配置文件中的hz来进行配置 。
# 代表每1s 运行 10次
hz 10
Redis 默认每 1 秒运行 10 次,也就是每 100 ms 执行一次,每次随机抽取一些设置了过期时间的 key(这边注意不是检查所有设置过期时间的key,而是随机抽取部分),检查是否过期,如果发现过期了就直接删除。 该定时任务的具体流程如下:
大家看最后一步,如果一致有超过25%的过期key,就会导致 Redis 一直去删除来释放内存,而删除是阻塞的。 所以,需要避免大量 key 过期早同一时期过期,这样可能需要重复删除多次才能降低到 25% 以下.
解决方案: 可以给缓存设置过期时间时加上一个随机值时间(在 EXPIREAT 和 EXPIRE 的过期时间参数上,加上一个一定大小范围内的随机数),使得每个key的过期时间分布开来,不会集中在同一时刻失效。 随机值我们团队的做法是:n * 3/4 + n * random() 。所以,比如你原本计划对一个缓存建立的过期时间为8小时,那就是6小时 + 0~2小时的随机值。 这样保证了均匀分布在 6~8小时之间。如图:
bigkey 是指含有较大数据或含有大量成员、列表数的 Key。以下是一些实际的例子:
bigkey 带来问题如下:
优化 Redis 的 bigkey 可以从以下几个方面入手:
优化步骤如下:
最后此篇关于Redis系列23:性能优化指南的文章就讲到这里了,如果你想了解更多关于Redis系列23:性能优化指南的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在这段令人惊叹的视频 ( https://www.youtube.com/watch?v=udix3GZouik ) 中,Alex Blom 谈到了 Ember 在移动世界中的“黑客攻击”。 在 22
我们希望通过我们的应用收集使用情况统计信息。因此,我们希望在服务器端的某个地方跟踪用户操作。 就性能而言,哪个选项更合适: 在 App Engine 请求日志中跟踪用户操作。即为每个用户操作写入一个日
在针对对象集合的 LINQ 查询的幕后究竟发生了什么?它只是语法糖还是发生了其他事情使其更有效的查询? 最佳答案 您是指查询表达式,还是查询在幕后的作用? 查询表达式首先扩展为“普通”C#。例如: v
我正在构建一个简单的照片库应用程序,它在列表框中显示图像。 xaml 是:
对于基于 Web 的企业应用程序,使用“静态 Hashmap 存储对象” 和 apache java 缓存系统有何优缺点?哪一个最有利于性能并减少堆内存问题 例如: Map store=Applica
我想知道在性能方面存储类变量的最佳方式是什么。我的意思是,由于 Children() 函数,存储一个 div id 比查找所有其他类名更好。还是把类名写在变量里比较好? 例如这样: var $inne
我已经阅读了所有这些关于 cassandra 有多快的文章,例如单行读取可能需要大约 5 毫秒。 到目前为止,我不太关心我的网站速度,但是随着网站变得越来越大,一些页面开始需要相当多的查询,例如一个页
最近,我在缓存到内存缓存之前的查询一直需要很长时间才能处理!在这个例子中,它花费了 10 秒。在这种情况下,我要做的就是获得 10 个最近的点击。 我感觉它加载了所有 125,592 行然后只返回 1
我找了几篇文章(包括SA中的一些问题),试图找到基本操作的成本。 但是,我尝试制作自己的小程序,以便自己进行测试。在尝试测试加法和减法时,我遇到了一些问题,我用简单的代码向您展示了这一点
这个问题在这里已经有了答案: Will Java app slow down by presence of -Xdebug or only when stepping through code? (
我记得很久以前读过 with() 对 JavaScript 有一些严重的性能影响,因为它可能对范围堆栈进行非确定性更改。我很难找到最近对此的讨论。这仍然是真的吗? 最佳答案 与其说 with 对性能有
我们有一个数据仓库,其中包含非规范化表,行数从 50 万行到 6 多万行不等。我正在开发一个报告解决方案,因此出于性能原因我们正在使用数据库分页。我们的报告有搜索条件,并且我们已经创建了必要的索引,但
我有一条有效的 SQL 语句,但需要很长时间才能处理 我有一个 a_log 表和一个 people 表。我需要在 people 表中找到给定人员的每个 ID 的最后一个事件和关联的用户。 SELECT
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
通常当我建立一个站点时,我将所有的 CSS 放在一个文件中,并且一次性定义与一组元素相关的所有属性。像这样: #myElement { color: #fff; background-
两者之间是否存在任何性能差异: p { margin:0px; padding:0px; } 并省略最后的分号: p { margin:0px; padding:0px } 提前致谢!
我的应用程序 (PHP) 需要执行大量高精度数学运算(甚至可能出现一共100个数字) 通过这个论坛的最后几篇帖子,我发现我必须使用任何高精度库,如 BC Math 或 GMP,因为 float 类型不
我一直在使用 javamail 从 IMAP 服务器(目前是 GMail)检索邮件。 Javamail 非常快速地从服务器检索特定文件夹中的消息列表(仅 id),但是当我实际获取消息(仅包含甚至不包含
我非常渴望开发我的第一个 Ruby 应用程序,因为我的公司终于在内部批准了它的使用。 在我读到的关于 Ruby v1.8 之前的所有内容中,从来没有任何关于性能的正面评价,但我没有发现关于 1.9 版
我是 Redis 的新手,我有一个包含数百万个成员(member) ID、电子邮件和用户名的数据集,并且正在考虑将它们存储在例如列表结构中。我认为 list 和 sorted set 可能最适合我的情
我是一名优秀的程序员,十分优秀!