最近在一个web api中使用了Redis做缓存 替换掉原来的 HttpRuntime.Cache
百度到 StackExchange.Redis 这个东东
一开始使用 一切正常 代码也很简洁
前两天 并发量增大了些 原来只有十几 增加到一百多的样子 然后就...不能用了...
运行不到一分钟就开始抛异常
StackExchange.Redis.RedisConnectionException: It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketFailure on PING
一时没有找到解决的办法 只有切换回HttpRuntime.Cache
百度+测试 搞了一天 也没找到可用的解决方案(想不到吧) 不过还是找到了一些原因
先测试了把连接创建给改单利模式
测试之后并没能解决这个问题 异常还是发送在创建连接的位置 虽然只调用了一次 改过几种连接字符串设置都不好使 改过abortConnect 改了不会抛出异常了 也不会写入缓存 timeout改了也没有用 最终还是要超时 异常就是红框的代码抛出的
测试代码差不多设这个样子 写的控制台应用程序 模拟成多线程访问
问题依旧
下面在创建线程前加一点休眠
噫 这个居然没有抛出异常 成功创建了连接 但是这个不太符合我接口的逻辑呀 不能每次写入缓存都休眠一会儿吧 而且这里的连接创建非常慢 四五秒的样子才成功
之后觉得可能是 ThreadPool 的问题
于是把ThreadPool的模拟换成了Task(说的Task也是ThreadPool实现的 不过好用一些)
这次居然成功了 连接获取很快 没有抛出异常 数据也成功写入redis
那么问题大概可以猜到了
ConnectionMultiplexer.Connect(configuration);是使用了ThreadPool中的线程来处理 如果ThreadPool中有任务排队 (测试中我没加Thread.Sleep(50);的代码 一开始就写入了大量的任务到ThreadPool ConnectionMultiplexer.Connect要等待我写入的任务执行完了才能使用线程池) 创建连接就会等待 然后就超时了
然而我仍然不知道怎么解决我web API遇到的问题 web api使用ThreadPool中的线程处理并发 而ThreadPool是.net自己在维护 只要在ConnectionMultiplexer.Connect之前线程池繁忙,创建连接就容易超时 在单利初始化创建连接之前,并发请求已经占用了ThreadPool 估计要换服务器或者做点其他预热什么的?
单利模式在这里也是有作用的
ConnectionMultiplexer.Connect准确的说还是非常缓慢的 可能0.1秒? 反正对应缓存来说已经很慢了 但是它创建出来的连接是可以复用的 不需要每次都释放又重新创建 复用就非常快了 单利模式解决复用问题
最终我想了一个奇怪的解决方案 在 Global.asax的 Application_Start里面调用一下RedisConnectionHelp.Instance 在处理并发请求之前先把单利的连接创建出来
什么?你问我Task和ThreadPool到底有啥区别? 嗯.......我去百度一下