.Net Core Web Api实践(四)填坑连接Redis时Timeout performing EVAL
前言:前两篇文章.net core+Redis+IIS+nginx实现Session共享中,介绍了使用Microsoft.Extensions.Caching.Redis实现Session共享的方法,但是高并发时会有连接Redis出现Timeout的问题,这篇文章将介绍该问题的解决方案。
1、环境及工具准备
操作系统:windows10
数据库:Redis
压力测试工具:JMeter(传送门)
2、背景介绍
项目迁移到.net core并上线以后,运行没多久接口就频繁罢工,容器没有挂,redis、mogodb、sql server全都正常,容器重启后可以正常一下,但是没过多久就又罢工了,最后只有通过docker logs命令挨个去寻找容器日志中记录的错误信息,结果发现了StackExchange.Redis.RedisTimeoutException: Timeout performing EVAL。这里说明下是.net core2.2版本,不知道3.1版本还会不会有这个问题。

3、问题重现
打开JMeter压力测试工具 ,添加一个http请求

使用上篇文章发布在docker的地址和请求参数

设置线程数为500,循环次数为3,并运行,从汇总报告中可以看出,错误率高达50%以上

使用docker logs查看容器日志,发现了同线上一样的Redis连接超时错误,且Redis数据中缓存的数量只有668(理论上应该是500*3=1500)


4、问题分析过程
(1)找到Redis组件注入的地方

(2)查看AddDistributedRedisCache源码,发现注入的是一个单例的IDistributedCache对象:

然后就发现RedisCache对象是用ConnectionMultiplexer管理Redis连接的

这里针对ConnectionMultiplexer对象做了线程安全

(3)进一步查看源码,也没有发现连接池的使用,而且从官网上的介绍来看,ConnectionMultiplexer中也没有连接池的概念,RedisCache对象中用于访问Redis数据库的私有属性_cache,并不是从连接池中获取对象,这样一来,在并发量较大的时候,会出现连接等待时间过长从而导致超时的问题,所以网上查看的类似将最小线程数设置大一些的解决方案并不可行;至于将TimeOut设置大一些,不仅不解决根本问题,还有悖于使用Redis的初衷。


5、解决方案
从第4步的分析来看,Microsoft.Extensions.Caching.Redis本身就不适合用于上篇文章介绍的Session共享方案,因为官网给出的注入对象,没有用连接池管理ConnectionMultiplexer,而ConnectionMultiplexer本身也没有池的概念。这里出两种解决方案:
(1)使用Sql Server替代Redis保存Session,这是我的一位同事找到的解决方案,并成功线上救火,这种方案代码实现简单,其它地方不需要改变。

(2)使用CSRedis组件,替代Microsoft.Extensions.Caching.Redis,具体实现方式如下:
安装nuget包

对照AddDistributedRedisCache,自定义AddDistributedCsRedisCache静态方法
public static class CsRedisTest
{
public static IServiceCollection AddDistributedCsRedisCache(this IServiceCollection services, CSRedis.CSRedisClient cSRedisClient)
{
if (services == null)
{
throw new ArgumentNullException("services");
} if (cSRedisClient == null)
{
throw new ArgumentNullException("cSRedisClient");
}
//if (setupAction == null)
//{
// throw new ArgumentNullException("setupAction");
//}
services.AddOptions();
//services.Configure(setupAction);
services.Add(ServiceDescriptor.Singleton<IDistributedCache, CsRedisCacheTest>(factory => {
return new CsRedisCacheTest(cSRedisClient);
}));
return services;
}
}
对照RedisCache类,自定义CsRedisCacheTest类,继承IDistributedCache接口,这里参考的是https://github.com/2881099/Microsoft.Extensions.Caching.CSRedis

修改Startup.cs的注册方式如下:

这里的defaultdatabase貌似只能设置为0,设置为其它值会报错,这点不如Microsoft.Extensions.Caching.Redis。
测试结果如下:
连接串poolSize为50,线程数500,循环次数3,测试通过(即Redis数据库成功缓存1500条数据,汇总报告中错误率为0)
连接串poolSize为50,线程数1000,循环次数3,测试不通过,出现超时问题,利用info clients命令查看Redis客户端连接数为51(50是应用程序的,1是我通过命令连接的)


连接串poolSize为100,线程数1000,循环数次数3,客户端连接数27,测试通过
连接串poolSize为100,线程数3000,循环数次数3,客户端连接数46,测试通过
连接串poolSize为100,线程数5000,循环数次数3,客户端连接数42,测试通过
连接串poolSize为100,线程数8000,循环数次数3,客户端连接数101,测试不通过
由此可见,不断调高线程数的情况下,应用程序还是会崩溃,但是poolSize设为100基本就够用了,假设产品用户量为100万,日活20万,最高同时在线用户3万,单服务入口最高1万访问量,上面压力测试发现是可以应对15000的同时访问量的。当然poolSize也可以设置得更高,毕竟Redis允许的最大客户端连接数是10000,在没有迹象表明poolSize设置较大值不会有任何负面作用的情况下,个人觉得不宜盲目调大。另外有兴趣的同学也可以相对的做下预警机制,比如poolSize设置了100,当Redis客户端连接数达到80时,向IT人员发送短信预警,届时可以调高poolSize值,避免系统崩溃。
6、结语
到这篇文章结束,.net core+Redis+Docker+k8s(或IIS+nginx)实现Session共享才算真正完结,建议这篇文章跟前两篇文章一起看,Redis连接超时的坑,算是最大的坑之一,所以前后花了这么多篇幅介绍,如果文章中哪些错误或值得改进的地方,也欢迎大家指出。
参考资料:
1、CSRedisCache实现: https://github.com/2881099/Microsoft.Extensions.Caching.CSRedis/blob/master/CSRedisCache.cs
2、Jemeter使用:https://www.cnblogs.com/monjeo/p/9330464.html
3、StackExchange.Redis官方介绍: https://stackexchange.github.io/StackExchange.Redis/PipelinesMultiplexers
.Net Core Web Api实践(四)填坑连接Redis时Timeout performing EVAL的更多相关文章
- .Net Core Web Api实践之中间件的使用(一)
前言:从2019年年中入坑.net core已半年有余,总体上来说虽然感觉坑多,但是用起来还是比较香的.本来我是不怎么喜欢写这类实践分享或填坑记录的博客的,因为初步实践坑多,文章肯定也会有各种错误,跟 ...
- .Net Core Web Api实践(三).net core+Redis+docker实现Session共享
前言:上篇文章介绍了.net core+Redis+IIS+nginx实现Session共享,本来打算直接说明后续填坑过程,但毕竟好多坑是用docker部署后出现的,原计划简单提一下.net core ...
- .Net Core Web Api实践(二).net core+Redis+IIS+nginx实现Session共享
前言:虽说公司app后端使用的是.net core+Redis+docker+k8s部署的,但是微信公众号后端使用的是IIS部署的,虽说公众号并发量不大,但领导还是使用了负载均衡,所以在介绍docke ...
- .net core web api + Autofac + EFCore 个人实践
1.背景 去年时候,写过一篇<Vue2.0 + Element-UI + WebAPI实践:简易个人记账系统>,采用Asp.net Web API + Element-UI.当时主要是为了 ...
- 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入
使用react全家桶制作博客后台管理系统 前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...
- ASP.NET Core Web API 最佳实践指南
原文地址: ASP.NET-Core-Web-API-Best-Practices-Guide 介绍 当我们编写一个项目的时候,我们的主要目标是使它能如期运行,并尽可能地满足所有用户需求. 但是,你难 ...
- [转]ASP.NET Core Web API 最佳实践指南
原文地址: ASP.NET-Core-Web-API-Best-Practices-Guide 转自 介绍# 当我们编写一个项目的时候,我们的主要目标是使它能如期运行,并尽可能地满足所有用户需求. 但 ...
- ASP.NET Core Web API下事件驱动型架构的实现(二):事件处理器中对象生命周期的管理
在上文中,我介绍了事件驱动型架构的一种简单的实现,并演示了一个完整的事件派发.订阅和处理的流程.这种实现太简单了,百十行代码就展示了一个基本工作原理.然而,要将这样的解决方案运用到实际生产环境,还有很 ...
- [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了
[译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...
随机推荐
- css图片填充的几种方式
当图片比例不固定时,想要让图片自适应,一般都会用background-size:cover/contain,但是这个只适用于背景图. img有个属性object-fit 属性值:object-fit: ...
- 如何理解springMVC?
springMVC 工作原理? 简单理解:客户端发送请求-->前端控制器接受客户端的请求DispathServelt-->找到处理器映射HandMapping-->找到处理器hand ...
- 应用九:Vue之国际化(vue-i18n)
vue-i18n是一款针对Vue.js 的国际化插件,具体应用步骤如下: 一.安装插件 npm install vue-i18n --save 二.在main.js中引入插件 import VueI1 ...
- 深入理解CSS盒模型(转)
转自:https://www.cnblogs.com/chengzp/p/cssbox.html 基本概念 盒模型的组成大家肯定都懂,由里向外content,padding,border,margin ...
- 2019-2-11-WPF-列表自动换行
title author date CreateTime categories WPF 列表自动换行 lindexi 2019-02-11 08:55:31 +0800 2019-02-11 08:5 ...
- 微软软件开发技术二十年回顾-API篇(转)
二. API篇 随着Windows操作系统开始占据主导地位,开发Windows平台下的应用程序成为人们的需要.当然,这也为传统的DOS程序员提供了一种新的编程方法-一种不受设备限制并由事件驱动的编程方 ...
- boostrap-非常好用但是容易让人忽略的地方【4】:Font Awesome
font-awesome基本用法 官方代码传送门 font-awesome在bootstrap中的特殊用法(这个才是重点) 要点归纳1(官方) 官方代码传送门 要点归纳2(我的) <a href ...
- 微信小程序酒店日历超强功能
首先利用date拿到年月日 月记得+1 ,因为是从0开始的 先遍历月份,跨年年+1 ,月归至1: 然后遍历天数, lastDat = new Date(val.year,val.month,0).ge ...
- 超简单本地mock假数据测试,模拟后台数据返回必杀技
温馨提示:急性子可以直接拉到最后观看方法步骤. 什么是mock? mock就是在开发过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试开发的方法. 使用mock有什么好处? ...
- Linux 学习笔记 4 创建、复制、移动、文件的基本操作
写在前面 通过上一节的学习,我们基本的了解到在Linux 里面对于设备的挂载.卸载以及设备存在的目录.挂载目录.都有了一个基本的了解 本节主要了解文件.以及目录的相关操作,比如文件.目录的创建.以及删 ...