광고


[Redis] C# client "StackExchange.Redis.Extensions" 소개 및 예제 Redis




1. StackExchange.Redis.Extensions

StackExchange.Redis로도 거의 모든 것을 할 수 있지만,
유저 정의 클래스 단위로 serialize/deserialize 하는 것이 불편하여 검색질 중 StackExchange.Redis.Extensions을 찾게 되었다.

찾고보니 이 녀석이 애초 목적도 목적이지만, 기존의 StackExchange.Redis보다 훨씬 편하다는 것을 알게 되었다.
Github 공홈에서는 다음과 같은 장점들을 나열하고 있다.
  • C# object를 Redis에 추가/삭제를 편리하게~! (애초 목적)
  • * 패턴 매칭을 이용한 복수의 key 검색
  • 복수의 C# object를 single round-trip으로 Redis에 쓰기/읽기 (Good)
  • Async 메쏘드들
  • Redis 서버 정보 얻어오기

이름처럼 StackExchange.Redis에 기반하여, 확장된 기능들을 편리하게 제공해 주는 녀석이다.
(공홈의 내용이 거의 전부지만, 이 블로그를 많이 참고하였다 : An easy way to use StackExchange.Redis)


2. 설치

NuGet 매니에서 "StackExchange.Redis.Extensions"로 검색하면 다음과 같이 5개의 결과가 나온다.
  • Core
  • Jil (Json serializer)
  • Newtonsoft (Json serializer)
  • MsgPack (Json serializer)
  • Protobuf (얜 머지?)

Serializer는 ISerializer의 기능을 제대로 구현해 놓은 녀석이라면, 아무 녀석이나 사용 가능하다.
(앞으로 이 문서는 Newtonsoft Json serializer를 기준으로 작성된다)

이 중에서, Newtonsoft를 설치하면 의존성에 의거하여, 다음과 같이 4개를 자동으로 설치해 준다.
  • Newtonsoft.Json
  • StackExchange.Redis
  • StackExchange.Redis.Extensions.Core
  • StackExchange.Redis.Extensions.Newtonsoft


3. 설정

요 녀석은 StackExchange.Redis와 다르게 App.config에 다음과 같이 설정을 해야 한다.

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration> 
  3.   <!-- StackExchange.Redis.Extensions -->
  4.   <configSections>
  5.     <section name="redisCacheClient"
  6.             type="StackExchange.Redis.Extensions.Core.Configuration.RedisCachingSectionHandler, StackExchange.Redis.Extensions.Core" />
  7.   </configSections> 
  8.   <redisCacheClient allowAdmin="true" ssl="false" connectTimeout="5000" database="0">
  9.     <hosts>
  10.       <add host="127.0.0.1" cachePort="6379"/>
  11.     </hosts>
  12.   </redisCacheClient> 
  13. </configuration>

이 과정에서 살짝 삽질을 했었는데, 보통 App.config을 열면 다음과 같이 되어 있다. (VS2015 기준)

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.     <startup>
  4.         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  5.     </startup>
  6. </configuration>

여기에다가 위 StackExchange 관련 설정을 추가하였더니 System.Configuration.ConfigurationErrorsException이 발생하였다.
이래저래 삽질하다가 기본 설정에 추가하는 게 아니라, 원래 있던 설정을 지우고 위 설정만 남겼더니 문제가 없어졌다.
왜 이런지는 조금 더 테스트를 해 봐야겠다 (추후 문서 보충하자)

이 방법은 App.config을 이용하는 방법이고, App.config 수정 방식이 싫다면 다음 방법을 사용할 수도 있다.
StackExchange.Redis의 ConnectionMultiplexer를 생성자로 넘기는 방식이다.
이 방법을 사용하면 App.config을 손대지 않아도 된다.

  1. var serializer = new NewtonsoftSerializer();
  2. // ConnectionMultiplexter.Connect(string configuration, ...)의
  3. // configuration이 App.config의 설정 내용을 대신해 주기 때문이다.
  4. ConnectionMultiplexer redisMaster =
  5.     ConnectionMultiplexer.Connect("127.0.0.1:6379" + ",allowAdmin=true,password=...");
  6.  
  7. var cacheClient = new StackExchangeRedisCacheClient(redisMaster, serializer);


4. 예제

  1. using System;
  2. using System.Collections.Generic;
  3. // for StackExchange.Redis.Extensions
  4. using StackExchange.Redis;
  5. using StackExchange.Redis.Extensions.Core;
  6. using StackExchange.Redis.Extensions.Newtonsoft;
  7.  
  8. namespace RedisTest2
  9. {
  10.     class User
  11.     {
  12.         public string Firstname;
  13.         public string Lastname;
  14.         public string Twitter;
  15.         public string Blog;
  16.     }
  17.  
  18.     class Program
  19.     {
  20.         // for Lazy singleton (thread-safe)
  21.         private static Lazy<StackExchangeRedisCacheClient> lazyCacheClient = null;
  22.  
  23.         static void Main(string[] args)
  24.         {
  25.             // 0. serializer / ICacheClient 생성            
  26.             var serializer = new NewtonsoftSerializer();
  27.  
  28.             // App.config에서 설정을 하였기에, 3가지 원형중 가장 간단한 원형으로 생성
  29.             lazyCacheClient = new Lazy<StackExchangeRedisCacheClient>(() =>
  30.             {
  31.                 return new StackExchangeRedisCacheClient(serializer);
  32.             });
  33.             var cacheClient = lazyCacheClient.Value;
  34.  
  35.             // 1. User 객체 쓰기
  36.             var user1 = new User()
  37.             {
  38.                 Firstname = "Ugo",
  39.                 Lastname = "Lattanzi",
  40.                 Twitter = "@imperugo",
  41.                 Blog = "http://tostring.it"
  42.             };
  43.  
  44.             // result : bool
  45.             // Add(key, value)
  46.             // Add(key, value, expiresIn(얼마뒤에))
  47.             // Add(key, value, expiresAt(언제)) <<- 여기선 이걸 씀
  48.             bool added = cacheClient.Add("user1", user1, DateTimeOffset.Now.AddMinutes(10));
  49.             if (added)
  50.             {
  51.                 Console.WriteLine("User1 has been updated to Redis");
  52.             }
  53.             else
  54.             {
  55.                 Console.WriteLine("User1 FAILED to update to Redis");
  56.             }
  57.  
  58.             // 2. User 객체 읽기
  59.             // value = Get<ValueType>(key)
  60.             User cachedUser = cacheClient.Get<User>("user1");
  61.             if (cachedUser != null)
  62.             {
  63.                 Console.WriteLine("User1 loaded from Redis");
  64.             }
  65.             Console.WriteLine();
  66.  
  67.             // 3. 한번에 여러 오브젝트 쓰기
  68.             //    Tuple<key, value>의 List 형식
  69.             IList<Tuple<string, User>> userList = new List<Tuple<string, User>>();
  70.  
  71.             var user2 = new User()
  72.             {
  73.                 Firstname = "Simone",
  74.                 Lastname = "Chiaretta",
  75.                 Twitter = "@simonech",
  76.                 Blog = "http://codeclimber.net.nz"
  77.             };
  78.  
  79.             var user3 = new User()
  80.             {
  81.                 Firstname = "Matteo",
  82.                 Lastname = "Pagani",
  83.                 Twitter = "@qmatteoq",
  84.                 Blog = "http://qmatteoq.com"
  85.             };
  86.  
  87.             userList.Add(Tuple.Create("user1", user1));
  88.             userList.Add(Tuple.Create("user2", user2));
  89.             userList.Add(Tuple.Create("user3", user3));
  90.  
  91.             bool listAdded = cacheClient.AddAll(userList);
  92.             if (listAdded)
  93.             {
  94.                 Console.WriteLine("UserList has been updated to Redis");
  95.             }
  96.             else
  97.             {
  98.                 Console.WriteLine("UserList FAILED to update to Redis");
  99.             }
  100.  
  101.             // 3. 한번에 여러 오브젝트 읽기
  102.             string[] keys = { "user1""user2""user3" };            
  103.             var cachedUserList = cacheClient.GetAll<User>(keys);
  104.             if (cachedUserList.Count != 0)
  105.             {
  106.                 Console.WriteLine("UserList loaded from Redis");
  107.             }
  108.             Console.WriteLine();
  109.  
  110.             // 4. 패턴을 이용한 복수의 key 찾기
  111.             var foundKeys = cacheClient.SearchKeys("user*");
  112.             Console.Write("Found keys : ");
  113.             foreach (var key in foundKeys)
  114.             {
  115.                 Console.Write("{0} ", key);
  116.             }
  117.             Console.WriteLine();
  118.  
  119.             // 5. Redis 메쏘드 직접 사용
  120.             // IDatabase를 가져와서 그냥 사용하면 된다
  121.             IDatabase dbMaster = cacheClient.Database;
  122.             dbMaster.StringSet("simpleKey""simpleValue:abcdefg");
  123.             string getValue = dbMaster.StringGet("simpleKey");
  124.             Console.WriteLine(getValue);
  125.             Console.WriteLine();
  126.  
  127.             // 6. 서버 정보 가져오기
  128.             // redis의 "info" 명령어와 동일한 정보를 얻어온다
  129.             // info는 Dictionary<string, string> 형식
  130.             var infoDict = cacheClient.GetInfo();
  131.             Console.WriteLine("--------------- ServerInfo --------------");
  132.             foreach (var info in infoDict)
  133.             {
  134.                 Console.WriteLine("{0} : {1} ", info.Key, info.Value);
  135.             }
  136.  
  137.             Console.Read();
  138.         }
  139.     }
  140. }


덧글

  • Woker 2017/01/09 15:31 # 삭제 답글

    좋은 글 잘 보고 갑니다!!
댓글 입력 영역