ServiceStack.Redis的问题与修正

Redis是开源、高性能的Key-value存储引擎。

最近我们在一个日访问量约1kw的网站上使用redis替换以前的memcache,成功将CPU从30%下降到15%,效果相当显著。

ServiceStack.Redis的问题与修正_第1张图片

ServiceStackRedis是最受欢迎的C#驱动之一。关于如何使用ServiceStackRedis请参见这里——使用ServiceStackRedis链接Redis简介

不过我们在使用ServiceStackRedis的线程池(PooledRedisClientManager)还是碰到了不少问题。

 1 链接数异常。

 一个webserver会占用80个链接。当15台webserver就过千了,这时会出现有些客户端链接不上的情况。

 解决方案:

 GetInActiveWriteClient方法中

//找下一个目标
//从当前读写指针的后面开始查找,而不是从0开始
var nextIndex = (WritePoolIndex + i) % writeClients.Length;
更改为
var nextIndex = i;
同时修改DisposeClient方法中将readClient.Active == false将DisposeConnection一下。线程就能很好的回收了。

效果:
在我们这样一个网站下,单台webserver大约会占用10个~15个链接,比之前的80个少了不少。

分析:

从代码上来看,作者的初衷是为了更快的找到空闲的线程,但是却认所有线程都不间断的使用,没有一个线程可能空闲。
如果站点较小,webserver不太多,不改问题也不大。不过我认为用长链接并不划算,因为与redis建立一个链接还是相对比较“便宜”的。

2 多台redis存储相同的内容。

相同的内容会冗余在所有redis中

解决方案

在GetInActiveWriteClient中加入int型参数来标识出使用那台redis

var start = 0;
var step = 1;
if (index > -1 && index < ReadWriteHosts.Count)
{
  start = index;
  step = ReadWriteHosts.Count;
}
//遍历读写池
//这个时候池是锁定的
for (var i = start; i < writeClients.Length; i += step)
{
  省略

这样线程池中就会按ReadWriteHosts的个数来顺序分配。

效果:

在进行读写时只需要使用key.GetHashCode方法获得一个hash值就能准确分配到其中一台redis上。保证所有的redis的数据不重复。



分类: 数据库技术
标签: redis, servicestack.redis, nosql
绿色通道: 好文要顶 关注我 收藏该文 与我联系
Goodspeed
关注 - 2
粉丝 - 23
+加关注
0
0
(请您对文章做出评价)
« 上一篇: supervisor 3.0a8-1 安装失败
» 下一篇: 使用Lambda实现递归

posted on 2011-07-26 16:05 Goodspeed 阅读(1792) 评论(4) 编辑 收藏

评论

#1楼 2011-07-26 16:52omeweb  

最好提交给作者
支持(0) 反对(0)
  

#2楼 2011-11-04 14:07古道  

按照楼主的想法,是不是如果其中一台服务器宕机,PooledRedisClientManager还要不断的向这台服务器发起连接?
支持(0) 反对(0)
  

#3楼 2012-08-23 13:28yibin  

1、我也ServiceStack的连接池上遇到一些问题:
比如我设定连接池中一共开50个连接,不断刷新页面,可以在Redis中看到有50个连接产生,但一旦达到50个连接,再刷新页面时,页面就处于等待状态,看起来像是之前建立的连接没有释放,导致没有多余的连接可用,导致排队产生,不知道这个问题如何解决?

2、后来改为一个静态属性,在静态构造函数里与Redis建立连接,但也有一个弊端,就是Redis如果重启了导致这个连接断开,应用方是不知道的,只能每次操作都Try-catch。
不知道有没有好的解决办法。
支持(0) 反对(0)
  

#4楼 2013-04-19 10:46wxf4150  

怎么你说的 怎么都是错的。还有好几个在下面评论里起哄!
多去读读源码:
http://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Redis/ServiceStack.Redis/PooledRedisClientManager.cs?r=961

DisposeClient 时只标记下readClient.Active = false,表示 当前链接已经是不活动了,但网络链接仍在链接池中 作者的做法这是很正确的。你还去搞个readClient.DisposeConnection,这样网络链接 都释放了,链接池里全是无网络链接的client了,每次使用还要新建。 哪里还有链接池的概念。

var nextIndex = (WritePoolIndex + i) % writeClients.Length;
作都更快的找到可用链接的做法同样是正确的。这里是求余,是从那个回定的几十个writeClient里取出一个,并不会新建别的client。
多看看。

瞎起哄的 也去看源码啊。
http://code.google.com/p/servicestack/source/browse/trunk/Common/ServiceStack.Redis/ServiceStack.Redis/PooledRedisClientManager.cs?r=961

你可能感兴趣的:(redis)