最近在一個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到底有啥區別? 嗯.......我去百度一下