【Azure Redis 缓存】Azure Redis 异常 - 因线程池Busy而产生的Timeout异常问题

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【Azure Redis 缓存】Azure Redis 异常 - 因线程池Busy而产生的Timeout异常问题

问题描述

StackExchange.Redis在使用线程池后,偶尔会出现Timeout awaiting response 或者 No connection is available to service this operation的异常消息,完整的错误异常如:

StackExchange.Redis.RedisTimeoutException: Timeout awaiting response (outbound=0KiB, inbound=0KiB, 20016ms elapsed, timeout is 20000ms), command=GET, next: GET VMD:LVSHFXXXXXXXX, inst: 0, qu: 10, qs: 1167, aw: True, bw: Inactive, rs: ReadAsync, ws: Writing, in: 0, serverEndpoint: Unspecified/xxxxredis.redis.cache.chinacloudapi.cn:6380, mgr: 9 of 10 available, clientName: RD00xxxxxxxx, IOCP: (Busy=3,Free=997,Min=200,Max=1000), WORKER: (Busy=367,Free=1680,Min=300,Max=2047), v: 2.0.601.3402 (Please take a look at this article for some common client-side issues that can cause timeouts: 

StackExchange.Redis.RedisConnectionException: No connection is available to service this operation: SET VMD:LVSHFXXXXXXXX; IOCP: (Busy=4,Free=996,Min=200,Max=1000), WORKER: (Busy=344,Free=1703,Min=300,Max=2047), Local-CPU: n/a

Timeout performing GET orderfortjw, inst: 5, mgr: Inactive, err: never, queue: 10, qu: 0, qs: 15, qc: 0, wr: 0, wq: 0, in: 1826, ar: 0, clientName: RD00155D45335D, serverEndpoint: Unspecified/order-api.redis.cache.chinacloudapi.cn:6380, keyHashSlot: 545, IOCP: (Busy=0,Free=1000,Min=100,Max=1000), WORKER: (Busy=35,Free=23764,Min=100,Max=23764)

 StackExchange.Redis.RedisTimeoutException: Timeout performing GET orderforvb1dm6g0m, inst: 6, mgr: Inactive, err: never, queue: 913, qu: 0, qs: 913, qc: 0, wr: 0, wq: 0, in: 65536, ar: 0, clientName: RD00155D45352D, serverEndpoint: Unspecified/order-api.redis.cache.chinacloudapi.cn:6380, keyHashSlot: 1255, IOCP: (Busy=0,Free=1000,Min=2,Max=1000), WORKER: (Busy=3,Free=23764,Min=2,Max=23764)

 

问题原因

在异常消息中,最重要的信息为IOCP, WORKER两部分, 这是因为CLR(Common Language Runtime公共语言运行库)有两种类型的线程, Worker" 和 "I/O Completion Port" (IOCP) 线程。

  • WORKER: 对于诸如处理 Task.Run(…)ThreadPool.QueueUserWorkItem(…) 方法这类事务,请使用WORKER线程。 需要在后台线程上进行工作时,CLR 中的各种组件也会使用这些线程。
  • IOCP: 进行异步 IO(例如从网络进行读取)时,使用 IOCP 线程

一旦Busy线程数达到Min线程数,ThreadPool 便会将插入新线程的速率限制为每 500 毫秒一个线程。如果Busy的工作多于配置的Min设置,则在处理某些工作时会出现一定的延迟,因为 ThreadPool 会等待发生以下两种情况之一。

  • 一个现有线程释放,以便处理工作。
  • 在 500 毫秒内没有任何现有线程释放,因此会创建一个新线程。

基本上,这意味着Busy线程数大于Min线程数,在应用程序处理网络流量之前可能需要付出 500 毫秒延迟。 如果 IOCP 或WORKER线程受到限制,则 StackExchange.Redis 可能会超时等异常。

  1. StackExchange.Redis.RedisTimeoutException: Timeout awaiting response ... IOCP: (Busy=3,Free=997,Min=200,Max=1000), WORKER: (Busy=367,Free=1680,Min=300,Max=2047)
  2. StackExchange.Redis.RedisConnectionException ... IOCP: (Busy=4,Free=996,Min=200,Max=1000), WORKER: (Busy=344,Free=1703,Min=300,Max=2047)

如以上的错误消息中,IOCP的线程数工作正常,没有超过Min值。但是Worker的线程数Busy状态分别为367,344都大于最小值(Min)300,所以出现RedisTimeoutException或RedisConnectionException异常。

 

解决办法

建议将 IOCP 和Worker 线程的最小配置值设置为大于默认值。此设置会影响复杂应用程序其他部分的性能,因此每个应用需要按照其特定需求来微调此设置。开始时设置为 200 或 300 会比较好,随后可进行测试并根据需要进行调整。

在.NET中的设置示例如下:

private readonly int minThreads = 200;
void Application_Start(object sender, EventArgs e)
{
    // Code that runs on application startup
    AreaRegistration.RegisterAllAreas();
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    ThreadPool.SetMinThreads(minThreads, minThreads);
}

 

参考资料

Redis 有关线程池增长的重要详细信息https://docs.microsoft.com/zh-cn/azure/azure-cache-for-redis/cache-management-faq#important-details-about-threadpool-growth

 

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
26天前
|
监控 NoSQL 安全
如何在 Redis 中正确使用多线程?
【10月更文挑战第16天】正确使用 Redis 多线程需要综合考虑多个因素,并且需要在实践中不断摸索和总结经验。通过合理的配置和运用,多线程可以为 Redis 带来性能上的提升,同时也要注意避免可能出现的问题,以保障系统的稳定和可靠运行。
37 2
|
26天前
|
存储 NoSQL Redis
Redis 新版本引入多线程的利弊分析
【10月更文挑战第16天】Redis 新版本引入多线程是一个具有挑战性和机遇的改变。虽然多线程带来了一些潜在的问题和挑战,但也为 Redis 提供了进一步提升性能和扩展能力的可能性。在实际应用中,我们需要根据具体的需求和场景,综合评估多线程的利弊,谨慎地选择和使用 Redis 的新版本。同时,Redis 开发者也需要不断努力,优化和完善多线程机制,以提供更加稳定、高效和可靠的 Redis 服务。
30 1
|
1月前
线程CPU异常定位分析
【10月更文挑战第3天】 开发过程中会出现一些CPU异常升高的问题,想要定位到具体的位置就需要一系列的分析,记录一些分析手段。
61 0
|
27天前
|
监控 Java
在实际应用中选择线程异常捕获方法的考量
【10月更文挑战第15天】选择最适合的线程异常捕获方法需要综合考虑多种因素。没有一种方法是绝对最优的,需要根据具体情况进行权衡和选择。在实际应用中,还需要不断地实践和总结经验,以提高异常处理的效果和程序的稳定性。
19 3
|
4天前
|
缓存 NoSQL 网络协议
【Azure Redis】因为Redis升级引发了故障转移后的问题讨论
3:对于Redis的Server Load指标,每秒创建连接数的并发值,是否有建议呢? 【答】:为了避免将缓存推到 100% 服务器负载,建议将连接创建速率保持在每秒 30 个以下。
|
27天前
|
监控 Java
捕获线程执行异常的多种方法
【10月更文挑战第15天】捕获线程执行异常的方法多种多样,每种方法都有其特点和适用场景。在实际开发中,需要根据具体情况选择合适的方法或结合多种方法来实现全面有效的线程异常捕获。这有助于提高程序的健壮性和稳定性,减少因线程异常带来的潜在风险。
19 1
|
27天前
|
监控 API
Hook 线程与捕获线程执行异常
【10月更文挑战第11天】Hook 线程和捕获线程执行异常是多线程编程中不可或缺的技术。通过深入理解和掌握这些方法,我们可以提高程序的稳定性和可靠性,更好地应对各种异常情况。同时,在实际应用中要注意平衡性能和准确性,制定合理的异常处理策略,以确保程序的正常运行。
27 1
|
2月前
|
消息中间件 存储 NoSQL
剖析 Redis List 消息队列的三种消费线程模型
Redis 列表(List)是一种简单的字符串列表,它的底层实现是一个双向链表。 生产环境,很多公司都将 Redis 列表应用于轻量级消息队列 。这篇文章,我们聊聊如何使用 List 命令实现消息队列的功能以及剖析消费者线程模型 。
96 20
剖析 Redis List 消息队列的三种消费线程模型
|
1月前
|
存储 运维 NoSQL
Redis为什么最开始被设计成单线程而不是多线程
总之,Redis采用单线程设计是基于对系统特性的深刻洞察和权衡的结果。这种设计不仅保持了Redis的高性能,还确保了其代码的简洁性、可维护性以及部署的便捷性,使之成为众多应用场景下的首选数据存储解决方案。
40 1
|
1月前
|
NoSQL Redis 数据库
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快
本文解释了Redis为什么采用单线程模型,以及为什么Redis单线程模型的效率和速度依然可以非常高,主要原因包括Redis操作主要访问内存、核心操作简单、单线程避免了线程竞争开销,以及使用了IO多路复用机制epoll。
44 0
Redis单线程模型 redis 为什么是单线程?为什么 redis 单线程效率还能那么高,速度还能特别快