要在多线程的情况下访问Redis
以前也用过ServiceStack.Redis去访问Redis
加上这玩意在Redis官方网站推荐指数排第一
果断就选择用它了
考虑到我是在多线程的环境下使用的
所以特意还去关注了它对多线程的支持
看着他们api图上大大的一排鸟语:ThreadSafe Access
我笑了
结果今天早上一到公司
一看数据
所有的东西全挂
回顾了一下上周上线的内容
一下就确定是ServiceStack.Redis在作怪
立马停掉
然后拿下日志分析
发现报了很多很诡异的异常...
例如:
- System.Runtime.Serialization.SerializationException: Type definitions should start with a '{', expecting serialized type 'SubscriptionModel', got string starting with: 1
- ServiceStack.Redis.RedisResponseException: Unknown reply on integer response: 43OK, sPort: 8223, LastCommand:
- ServiceStack.Redis.RedisResponseException: Unexpected reply: +OK, sPort: 8223, LastCommand:
然后东西就不明不白的假死了
看了下我的代码
所有可能的异常都处理了啊
这些小小的异常根本不可能搞死我的程序啊
于是猜想难道是ServiceStack.Redis内部的机制导致内存溢出了?
找运维查了下日志
一切正常
一点风吹草动都没有
于是拿着代码在本地各种疯跑各种乱七八糟调试
基本上出现的异常都被还原了
但是我的代码还是没死啊...
心里面一万头草泥马在奔腾啊...
然后再去运维那要了更详细的日志
回过头来看测试环境的程序
竟然完美的还原了线上的场景
跟进去一看
所有的线程都卡在Redis的Get方法里
这是什么情况?!
确定了下Redis没有挂
那就只能把问题锁定在ServiceStack.Redis里咯
不由怀疑
这玩意到底支持多线程不哦...
然后详细看了下ServiceStack.Redis的文档
然后发现一个惊天的秘密:
这坑爹的ServiceStack.Redis不支持我们传统认为的线程安全啊
ServiceStack.Redis对多线程采用的是连接池
也就是说:
每一个线程可以从连接池里获取一个连接供本线程使用
在使用完毕过后还回给连接池
这样来保证每一个线程使用的Redis连接都是独立的而不会互相干扰
这就是ServiceStack.Redis所谓的ThreadSafe Access
ServiceStack.Redis就是这样来保证线程安全的...
坑爹呢这是...
我们传统意义的线程安全可是多个线程并发访问一个对象啊
而不是多个线程访问不同的对象啊...
都怪我学艺不精啊...
竟然不知道还有这种ThreadSafe Access啊...
这个东西本身有自己的线程安全
不过它的线程安全是类似于java的ThreadLocal那种
就是每一个线程你可以自己去获取自己单独用的redis客户端
但是不能几个线程公用一个
所以基本就只有两种了:
每个线程自己去获取自己的redis客户端
如果公用一个客户端
自己手动加锁