標籤:style blog color io os 使用 ar for sp
現在越來越多的開發人員使用service-stack.redis 來進行redis的訪問,但是擷取redisclient的方式有多種方式,其中有一種從緩衝池擷取client的方式很是得到大家的認可。
1 List<string> listWrite = new List<string>() { "[email protected]:6380" }; 2 List<string> readHosts = new List<string>() { "192.168.8.245:6381", "192.168.8.245:6382" }; 3 PooledRedisClientManager clientManager = PoolManagerFactory.CreateManager(listWrite.ToArray(), readHosts.ToArray()); 4 ///可以在緩衝管理器中加入密碼驗證 因為沒有對應的密碼欄位顯示 5 ///通過getClient擷取一個client 串連 6 using (IRedisClient redisClient = clientManager.GetClient()) 7 { 8 IRedisTypedClient<Phone> phones = redisClient.As<Phone>(); 9 10 Phone phoneFive = phones.GetValue("5");11 if (phoneFive == null)12 {13 phoneFive = new Phone()14 {15 ID = 5,16 Manufacturer = "Nokia",17 Model = "guozhiqi",18 Owner = new Person()19 {20 21 ID = 1,22 Name = "袁金州",23 Surname = "Old"24 }25 };26 phones.SetEntry(phoneFive.ID.ToString(), phoneFive);27 }28 Console.WriteLine("OwnerID" + phones.GetValue("5").Owner.Name);29 }
請注意上面代碼的第五行,using (IRedisClient redisClient = clientManager.GetClient()){}
通過clientManager.getClient方法來擷取一個串連,我們在ado.net中也是採用這種方式,而且效能很高。我們認為這種方式的工作方式肯定是首先從緩衝池中擷取一條串連,然後執行using裡面的代碼,最後dispose。但是有時候這種方式在稍微訪問量大的時候效能很低,什麼原因呢?
1 /// <summary> 2 /// Returns a Read/Write client (The default) using the hosts defined in ReadWriteHosts 3 /// 返回可以讀寫的 用戶端串連 預設的 使用定義在readWriteHosts中的伺服器位址 4 /// </summary> 5 /// <returns></returns> 6 public IRedisClient GetClient() 7 { 8 lock (writeClients) 9 {10 AssertValidReadWritePool();11 12 RedisClient inActiveClient;13 while ((inActiveClient = GetInActiveWriteClient()) == null)14 {15 if (PoolTimeout.HasValue)16 {17 // wait for a connection, cry out if made to wait too long18 if (!Monitor.Wait(writeClients, PoolTimeout.Value))19 throw new TimeoutException(PoolTimeoutError);20 }21 else22 Monitor.Wait(writeClients, RecheckPoolAfterMs);23 }24 25 WritePoolIndex++;26 inActiveClient.Active = true;27 28 if (this.ConnectTimeout != null)29 {30 inActiveClient.ConnectTimeout = this.ConnectTimeout.Value;31 }32 33 if (this.SocketSendTimeout.HasValue)34 {35 inActiveClient.SendTimeout = this.SocketSendTimeout.Value;36 }37 if (this.SocketReceiveTimeout.HasValue)38 {39 inActiveClient.ReceiveTimeout = this.SocketReceiveTimeout.Value;40 }41 if (this.IdleTimeOutSecs.HasValue)42 {43 inActiveClient.IdleTimeOutSecs = this.IdleTimeOutSecs.Value;44 }45 46 inActiveClient.NamespacePrefix = NamespacePrefix;47 48 //Reset database to default if changed49 if (inActiveClient.Db != Db)50 {51 inActiveClient.ChangeDb(Db);52 }53 54 return inActiveClient;55 }56 }
這是service-stack.redis中getClient的實現,但是我們發現了一個問題就是,他只從主 redis中擷取串連,不可能返回slave 的readonly 串連。
如果緩衝設定為5,那麼如果同時500個請求,還是會有效能影響的,因為完全忽略了slave的讀的功能。
如果要寫,我們可以調用clientManager.GetClient() 來擷取writeHosts的redis執行個體。
如果要讀,我們可以調用clientManager.GetReadOnlyClient()來擷取僅僅是readonlyHost的redis執行個體。
如果你嫌麻煩,那麼完全可以使用clientManager.GetCacheClient() 來擷取一個串連,他會在寫的時候調用GetClient擷取串連,讀的時候調用GetReadOnlyClient擷取串連,這樣可以做到讀寫分離,從而利用redis的主從複製功能。
Service-stack.redis 使用PooledRedisClientManager 速度慢的原因之一