Azure WebJob中.NET 3.1应用Redis HMGET超时异常排查
我有一个部署在Azure WebJob上的.NET 3.1应用,使用Azure Redis作为缓存服务。当应用尝试从缓存获取值时,会间歇性触发如下Timeout Exception:
Exception : Timeout awaiting response (outbound=0KiB, inbound=0KiB,
5546ms elapsed, timeout is 5000ms), command=HMGET, next: HMGET
App_Certificate, inst: 0, qu: 0, qs: 2, aw: False, rs: ReadAsync, ws:
Idle, in: 0, serverEndpoint: [redis.server.host.taken.out]:6380, mc:
1/1/0, mgr: 10 of 10 available, clientName: xxxxxxxxxxxxxx, IOCP:
(Busy=0,Free=1000,Min=4,Max=1000), WORKER:
(Busy=2,Free=680,Min=4,Max=682), v: 2.2.4.27433 (Please take a look at
this article for some common client-side issues that can cause
timeouts:
https://stackexchange.github.io/StackExchange.Redis/Timeouts)
重启WebJob后该问题消失,请问可能的故障原因是什么?
Redis配置代码
services.AddStackExchangeRedisCache(options => { options.Configuration = configuration.GetConnectionString("RedisConnection"); options.InstanceName = string.Concat(applicationName, "_"); });
Redis实现代码
public static class DistributedCacheExtensions { public static async Task SetRecordAsync<T>(this IDistributedCache cache, string recordId, T data, TimeSpan? absoluteExpiryTime = null, TimeSpan? unusedExpiryTime = null) { var options = new DistributedCacheEntryOptions() { AbsoluteExpirationRelativeToNow = absoluteExpiryTime ?? TimeSpan.FromMinutes(60), SlidingExpiration = unusedExpiryTime }; var jsonData = JsonSerializer.Serialize(data); await cache.SetStringAsync(recordId, jsonData, options); } public static async Task<T> GetRecordAsync<T>(this IDistributedCache cache, string recordId) { var jsonData = await cache.GetStringAsync(recordId); if (jsonData is null) { return default(T); } return JsonSerializer.Deserialize<T>(jsonData); } }
可能的故障原因分析
- StackExchange.Redis版本缺陷:你使用的版本是2.2.4.27433,该版本存在多个已知的连接管理、超时相关bug,后续稳定版本(如2.6.x及以上)已修复此类问题,升级版本大概率能解决间歇性超时。
- 连接资源泄漏:虽然当前错误显示连接池还有余量,但长时间运行中若存在连接未正确归还的场景(比如异常导致连接未释放),会逐步耗尽可用连接,重启WebJob会重建连接池,暂时恢复正常。
- WebJob资源累积问题:WebJob运行过程中若出现内存碎片、CPU占用攀升等资源瓶颈,会间接拖慢Redis客户端的IO响应。重启后资源重置,问题暂时消失。
- Azure Redis服务器端临时高负载:缓存失效风暴、突发高并发请求会导致Redis服务器响应延迟,触发客户端超时。重启WebJob相当于重建连接,暂时避开了服务器高负载时段,但根源是服务器压力问题。
- 连接配置参数缺失:当前配置未指定连接池大小、超时时间等关键参数,默认的5000ms超时在网络波动时可能不足,或连接池容量无法应对峰值并发,可通过连接字符串添加
maxPoolSize、connectTimeout、syncTimeout等参数优化。 - 异步操作阻塞:若业务代码中存在用
.Result/.Wait()同步阻塞异步Redis调用的情况,会导致线程池阻塞,这种问题会随运行时间累积,重启后线程池恢复正常,超时暂时消失。
内容的提问来源于stack exchange,提问作者mahmoudmh

