【Azure Redis 缓存 Azure Cache For Redis】Redis性能问题,发现Server Load非常的高,导致正常连接/操作不成功

简介: 【Azure Redis 缓存 Azure Cache For Redis】Redis性能问题,发现Server Load非常的高,导致正常连接/操作不成功

问题描述

在正常使用Azure Redis的服务中,突然发现Redis 的CPU达到了100%, 正常的使用中发现性能问题严重。从Redis的门户图表中,观察到CPU, Connection,Lentency,Server Load都出现高的情况

CPU

Server Load

Lentency(Redis处理请求的延迟情况)

Connection(客户端连接数情况)

 

 

 

 

 

 

 

 

 

 

 

 

问题分析

根据以上的图表发现,在Connection高的情况下导致了CPU上升并持续到100%, 引起了Server Load比较高(有时达到100%),从而导致在整个Redis的延迟升高。

在Redis创建一个新的连接时,是非常昂贵的高消耗操作。同时在Azure中,每一种定价级别的Redis都有连接数的限制,如果达到限制都会导致性能问题。而根据Reids的官方文档说明,当前连接数就是因为超过了最大上限。

如基本层的连接数限制为(https://www.azure.cn/pricing/details/cache/)

缓存名称 缓存大小 基本 网络性能 客户端连接数量
C0 250 MB ¥0.14片/节点/小时(约¥104.16 /月) 256
C1 1 GB ¥0.35片/节点/小时(约¥260.40 /月) 中等 1000
C2 2.5 GB ¥0.57片/节点/小时(约¥424.08 /月) 中等 2000
C3 6 GB ¥1.14片/节点/小时(约 ¥848.16 /月) 5000
C4 13 GB ¥1.33片/节点/小时(约 ¥989.52 /月) 中等 10000
C5 26 GB ¥2.66片/节点/小时(约 ¥1979.04 /月) 15000
C6 53 GB ¥5.31片/节点/小时(约¥3950.64 /月) 最高 20000

 

 

 

 

 

 

 

 

 

 

而在处理请求的并发和性能上,可以参考(https://docs.azure.cn/zh-cn/azure-cache-for-redis/cache-planning-faq#azure-cache-for-redis-performance):

定价层 大小 CPU 核心数 可用带宽 1 KB 值大小 1 KB 值大小
标准缓存大小     兆位/秒(Mb/秒)/兆字节/秒(MB/秒) 非 SSL 请求数/秒 (RPS) SSL 请求数/秒 (RPS)
C0 250 MB 共享 100/12.5 15,000 7,500
C1 1 GB 1 500/62.5 38,000 20,720
C2 2.5 GB 2 500/62.5 41,000 37,000
C3 6 GB 4 1000/125 100,000 90,000
C4 13 GB 2 500/62.5 60,000 55,000
C5 26 GB 4 1,000 / 125 102,000 93,000
C6 53 GB 8 2,000 / 250 126,000 120,000

 

 

 

 

 

 

 

 

 

 

 

解决办法

使用连接池来改善连接问题, 如JedisPool,可以参考GitHub中的说明:https://gist.github.com/JonCole/925630df72be1351b21440625ff2671f#use-jedispool, (如链接不可访问,可以点击[转] Azure Redis Best Practices - Java)参考示例代码:

9     private static JedisPool pool;
 15     private static JedisPoolConfig config;
 16
 17     // Should be called exactly once during App Startup logic.
 18     public static void initializeSettings(String host, int port, String password, int connectTimeout, int operationTimeout) {
 19         Redis.host = host;
 20         Redis.port = port;
 21         Redis.password = password;
 22         Redis.connectTimeout = connectTimeout;
 23         Redis.operationTimeout = operationTimeout;
 24     }
 25
 26     // MAKE SURE to call the initializeSettings method first
 27     public static JedisPool getPoolInstance() {
 28         if (pool == null) { // avoid synchronization lock if initialization has already happened
 29             synchronized(staticLock) {
 30                 if (pool == null) { // don't re-initialize if another thread beat us to it.
 31                     JedisPoolConfig poolConfig = getPoolConfig();
 32                     boolean useSsl = port == 6380 ? true : false;
 33                     int db = 0;
 34                     String clientName = "MyClientName"; // null means use default
 35                     SSLSocketFactory sslSocketFactory = null; // null means use default
 36                     SSLParameters sslParameters = null; // null means use default
 37                     HostnameVerifier hostnameVerifier = new SimpleHostNameVerifier(host);
 38                     pool = new JedisPool(poolConfig, host, port, connectTimeout,operationTimeout,password, db,
 39                             clientName, useSsl, sslSocketFactory, sslParameters, hostnameVerifier);
 40                 }
 41             }
 42         }
 43         return pool;
 44     }
 45
 46     public static JedisPoolConfig getPoolConfig() {
 47         if (config == null) {
 48             JedisPoolConfig poolConfig = new JedisPoolConfig();
 49
 50             // Each thread trying to access Redis needs its own Jedis instance from the pool.
 51             // Using too small a value here can lead to performance problems, too big and you have wasted resources.
 52             int maxConnections = 200;
 53             poolConfig.setMaxTotal(maxConnections);
 54             poolConfig.setMaxIdle(maxConnections);
 55
 56             // Using "false" here will make it easier to debug when your maxTotal/minIdle/etc settings need adjusting.
 57             // Setting it to "true" will result better behavior when unexpected load hits in production
 58             poolConfig.setBlockWhenExhausted(true);
 59
 60             // How long to wait before throwing when pool is exhausted
 61             poolConfig.setMaxWaitMillis(operationTimeout);
 62
 63             // This controls the number of connections that should be maintained for bursts of load.
 64             // Increase this value when you see pool.getResource() taking a long time to complete under burst scenarios
 65             poolConfig.setMinIdle(50);
 66
 67             Redis.config = poolConfig;
 68         }
 69
 70         return config;
 71     }
114 }

如PHP, NodeJS, ASP.Net的代码,都可以在以上的GitHub中找到示例代码。

 

同时,也非常推荐在代码中使用Lazy模式。

Reconnecting with Lazy<T> pattern

We have seen a few rare cases where StackExchange.Redis fails to reconnect after a connection blip (for example, due to patching). Restarting the client or creating a new ConnectionMultiplexer will fix the issue. Here is some sample code that still uses the recommended Lazy<ConnectionMultiplexer>pattern while allowing apps to force a reconnection periodically. Make sure to update code calling into the ConnectionMultiplexer so that they handle any ObjectDisposedException errors that occur as a result of disposing the old one.

1 using System;
  2 using System.Threading;
  3 using StackExchange.Redis;
  4
  5 static class Redis
  6 {
 21     static string connectionString = "TODO: CALL InitializeConnectionString() method with connection string";
 22     static Lazy<ConnectionMultiplexer> multiplexer = CreateMultiplexer();
 23
 24     public static ConnectionMultiplexer Connection { get { return multiplexer.Value; } }
 25
 93
 94     private static Lazy<ConnectionMultiplexer> CreateMultiplexer()
 95     {
 96         return new Lazy<ConnectionMultiplexer>(() => ConnectionMultiplexer.Connect(connectionString));
 97     }

参考资料

Redis Best Practices: https://gist.github.com/JonCole/925630df72be1351b21440625ff2671f#reuse-connections (如链接不可访问,可以点击[转]Azure Redis Best Practices - PHP)

Azure Redis 缓存性能: https://docs.azure.cn/zh-cn/azure-cache-for-redis/cache-planning-faq#azure-cache-for-redis-performance

Reuse Connections: https://gist.github.com/JonCole/925630df72be1351b21440625ff2671f#php

Reuse Connections

The most common problem we have seen with PHP clients is that they either don't support persistent connections or the ability to reuse connections is disabled by default. When you don't reuse connections, it means that you have to pay the cost of establishing a new connection, including the SSL/TLS handshake, each time you want to send a request. This can add a lot of latency to your request time and will manifest itself as a performance problem in your application. Additionally, if you have a high request rate, this can cause significant CPU churn on both the Redis client-side and server-side, which can result in other issues.

As an example, the Predis Redis client has a "persistent" connection property that is false by default. Setting the "persistent" property to true will should improve behavior drastically.

相关文章
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
缓存 NoSQL Java
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是Redis+Caffeine构建高性能二级缓存,废话不多说直接开始~
1875 0
|
11月前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
1006 25
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
460 1
Redis专题-实战篇二-商户查询缓存
|
11月前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
1936 3
|
12月前
|
存储 缓存 NoSQL
Redis持久化深度解析:数据安全与性能的平衡艺术
Redis持久化解决内存数据易失问题,提供RDB快照与AOF日志两种机制。RDB恢复快、性能高,但可能丢数据;AOF安全性高,最多丢1秒数据,支持多种写回策略,适合不同场景。Redis 4.0+支持混合持久化,兼顾速度与安全。根据业务需求选择合适方案,实现数据可靠与性能平衡。(238字)
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
缓存 监控 Linux
Linux系统清理缓存(buff/cache)的有效方法。
总结而言,在大多数情形下你不必担心Linux中buffer与cache占用过多内存在影响到其他程序运行;因为当程序请求更多内存在没有足够可用资源时,Linux会自行调整其占有量。只有当你明确知道当前环境与需求并希望立即回收这部分资源给即将运行重负载任务之前才考虑上述方法去主动干预。
2713 10
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
440 32
|
缓存 NoSQL Java
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
405 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡