尝试通过ServiceStack.Redis读取Redis列表时,间歇性出现以下错误:“无法从传输连接读取数据:已建立的连接被主机中的软件中止了”。我想知道我如何使用ServiceStack可靠地连接和池化Redis的整个概念是否是错误的。这是我使用密封类和单例模式进行连接的代码:
public sealed class RedisClientBase { public BasicRedisClientManager Redis; private static readonly RedisClientBase instance = new RedisClientBase(); private RedisClientBase() { Redis = new BasicRedisClientManager("mypassword@localhost:6379"); } public static RedisClientBase Instance { get { return instance; } } }
然后,我实例化另一个使用单例的类:
public class RedisBarSetData { private static RedisClient Redis; protected IRedisTypedClient<BarSet> redisBarSetClient; protected string instrument_key; public RedisBarSetData() { Redis = (RedisClient)RedisClientBase.Instance.Redis.GetClient(); redisBarSetClient = Redis.As<BarSet>(); } ~RedisBarSetData() { if (Redis != null) Redis.Dispose(); } public List<BarSet> getData(BarSets data) { setKeys(data); // instrument_key is set in here var redisBarSetClientList = redisBarSetClient.Lists[instrument_key]; List<BarSet> barSetData; barSetData = redisBarSetClientList.GetAll(); // <-- exception here (sometimes) return(barSetData); } }
这又是从“服务” DTO回调中实例化和调用的:
public class JmaSetsService : Service { public object Get(JmaSets request) { RedisBarSetData barSetData = new RedisBarSetData(); BarSets barSets = new BarSets(request); barSetList = barSetData.getData(barSets); return barSetList; } }
然后,我使用“邮递员”发布到该路线。多数点击“发送”会返回数据。有些例外。例外是尝试从代码中以注释“ <-例外”指示的redis读取内容时。现在,另一点是,我最近通过设置配置文件将Redis配置为使用密码。我提到这一点是因为我之前不记得有这个问题,但这也不可能相关,不知道。
就释放Redis连接而言,我的想法是我的析构函数调用Redis。当RedisBarSetData()超出范围时处置。这是处理它的可靠方法还是有更好的方法?我看到有人在获得池化客户端时使用“ using”语句,但是我在类中只有一个地方有很多“ using”语句,而不是调用:“ Redis =(RedisClient)RedisClientBase.Instance.Redis .GetClient();” 如果我有很多用于该类的方法,那么我必须在每个方法中重复执行代码吗?
您不应持有RedisClient或IRedisTypedClient<BarSet>封装了非线程安全的Redis TCP连接的任何单例实例。相反,您可以保留-的单例实例,IRedisClientsManager这是提供线程安全的Redis Client Factory(如数据库连接池)的目的。
RedisClient
IRedisTypedClient<BarSet>
IRedisClientsManager
如果您还使用ServiceStack Services,则在ServiceStack的IOC中注册依赖项会更容易,因此IRedisClientsManager可以像其他任何依赖项一样注入,例如AppHost.Configure():
AppHost.Configure()
container.Register<IRedisClientsManager>(c => new BasicRedisClientManager("mypassword@localhost:6379"));
这将允许您base.Redis在ServiceStack Services中使用RedisClient属性,例如:
base.Redis
public class JmaSetsService : Service { public object Get(JmaSets request) { var redisBarSets = base.Redis.As<BarSet>(); return redisBarSets.Lists[instument_key].GetAll(); } }
如果您使用base.Redis,则不必显式处理RedisClient,因为它已经 由Service自动处理,即:
public class Service { ... public virtual void Dispose() { if (redis != null) redis.Dispose(); ... } }
您还可以IRedisClientsManager像其他任何依赖项一样,使用公共属性或Constructor参数将其注入自己的类中,例如:
public class RedisBarSetData { public virtual IRedisClientsManager RedisManager { get; set; } private IRedisClient redis; public virtual IRedisClient Redis { get { return redis ?? (redis = RedisManager.GetClient()); } } public override void Dispose() { if (redis != null) redis.Dispose(); } public List<BarSet> getData(BarSets data) { setKeys(data); // instrument_key is set in here return Redis.As<BarSet>().Lists[instrument_key].GetAll(); } }
然后,您可以使用以下方法在ServiceStack的IOC中进行注册和自动连线:
container.RegisterAutoWired<RedisBarSetData>();
然后,您可以将其用作服务中的依赖项:
public class JmaSetsService : Service { public RedisBarSetData RedisBarSetData { get; set; } public object Get(JmaSets request) { return RedisBarSetData.getData(new BarSets(request)); } }
创建您自己的基类的一种替代方法是从预先存在的LogicBase基类继承,该基类已经具有IRedisClientsManager属性并且位于样板之上。