닷넷프레임워크에서 Redis 사용하기

7,854 views
7,116 views

Published on

Published in: Technology
0 Comments
21 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
7,854
On SlideShare
0
From Embeds
0
Number of Embeds
682
Actions
Shares
0
Downloads
71
Comments
0
Likes
21
Embeds 0
No embeds

No notes for slide

닷넷프레임워크에서 Redis 사용하기

  1. 1. 닷넷에서 Redis 사용하기 티쓰리엔터테인먼트 모바일 1팀 공통 기술 개발팀 최흥배 과장
  2. 2. Redis ?????
  3. 3. Key-Value, Memory DB
  4. 4. Redis v2.2.12 맛보기 http://www.slideshare.net/knight1128/redis-8896084
  5. 5. REDIS 연구노트 http://kerocat.tistory.com/1
  6. 6. REDIS 공부 http://blog.naver.com/forioso/10173379225
  7. 7. Redis 설치  http://cs-arthur.tistory.com/113  http://misoin.tistory.com/1  http://blog.outsider.ne.kr/763
  8. 8. .NET과 Redis
  9. 9. Redis의 .NET 라이브러리로 'ServiceStack.Redis'와 'BookSleeve'가 있다. 둘 다 Redis 공식 라이브러리 이다
  10. 10. 추천!!! BookSleeve Stack Overflow에서 근무하고 protobuf-net을 만든 Marc Gravell씨가 만들었다
  11. 11. "모든 것이 비동기로 파이프라인으로 동작 한다"
  12. 12. 파이프닝 Client: INCR X Server: 1 Client: INCR X Server: 2 Client: INCR X Server: 3 Client: INCR X Server: 4 Client: INCR X Client: INCR X Client: INCR X Client: INCR X Server: 1 Server: 2 Server: 3 Server: 4
  13. 13. 파이프닝을 사용하면 클라이 언트와 서버간 통신이 1번으 로 끝난다. 단순히 GET, SET 뿐만이 아 닌 다양한 조작을 파이프닝 할 수 있다
  14. 14. 설치
  15. 15. var connection = new RedisConnection("127.0.0.1"); await connection.Open(); var x1 = connection.Strings.Increment(db: 0, key: "X"); var x2 = connection.Strings.Increment(db: 0, key: "X"); var x3 = connection.Strings.Increment(db: 0, key: "X"); var x4 = connection.Strings.Increment(db: 0, key: "X"); await Task.WhenAll(x1, x2, x3, x4); // 모든 완료를 기다린다. // 결과 표시 Console.WriteLine("{0}, {1}, {2}, {3}", x1.Result, x2.Result, x3.Result, x4.Result);
  16. 16. BookSleeve는 모든 조작이 비동기이기 때문에 반환 값 은 Task 형이 된다. 또 C# 5.0 에서 생긴 async/await 메소드를 사용 하면 비동기 조작을 활용하 기 쉬워진다
  17. 17. 암묵적 파이프닝  [예제 - 1]은 명시적으로 파이프라인을 사용하지 않고 있 다.  BookSleeves는 내부에서 블럭킹 큐를 사용하여 명령어 를 축척하고 있다.  또 큐가 비었는지 감시하고, 명령어를 보내는(네트워크로) 워커가 동작하고 있다.  워커가 동작할 때 큐에 복수의 명령어가 축척되면 이것 들이 모두 일괄적으로 파이프닝으로 보낸다.  즉 같은 타이밍에 발행된 명령어는 자동적으로 파이프닝 화 된다.  또 네트워크 접근은 비동기 I/O로 소켓 통신을 하므로 파 이프닝 송신 동안의 대기 시간은 최소화 시킨다
  18. 18. 연결 관리 RedisConnection 오브젝트(=Redis 서버로의 접속)는 단독으로 열지 않고 공유 하고 있다. 접속을 관리하도록 아래와 같은 코드를 준비한다 public static class RedisConnectionManager { static RedisConnection connection; static object connectionLock = new object(); public static RedisConnection GetConnection() { if ((connection == null) || ( (connection.State != RedisConnectionBase.ConnectionState.Open) && (connection.State != RedisConnectionBase.ConnectionState.Opening) )) { lock (connectionLock) { if ((connection == null) || ( (connection.State != RedisConnectionBase.ConnectionState.Open) && (connection.State != RedisConnectionBase.ConnectionState.Opening) )) { connection = new RedisConnection("127.0.0.1"); // 접속 설정은 변경한다 connection.Wait(connection.Open()); } } } return connection; } }
  19. 19. var redis = RedisConnectionManager.GetConnection(); await redis.Strings.Set(db: 0, key: "jacking", value: "흥배"); var value = await redis.Strings.Get(db: 0, key: "jacking"); RedisConnection은 모든 요청에서 공유된다. ASP.NET에서는 모든 독립된 리퀘스트, 관련 없는 모 든 다른 명령어가 파이프닝화 되어 모아서 보내므로 큰 폭으로 Round Trip Time 이 줄어든다
  20. 20. BookSleeve 좀 귀찮은 -_-
  21. 21. 왜? BookSleeve 에서 제공하는 API는 원시 수준으로 대부분의 반환형이 byte[] 이다. 그래서 대부분 시리얼라이즈를 통해서 오브젝트로 변환해야 한다
  22. 22. CloudStructures https://github.com/neuecc/CloudStructures
  23. 23. 직렬화, 접속 관리, 클라이언트 사이드에서 분산, .config 파일에서 설정 읽기 BookSleeve
  24. 24. var settings = new RedisSettings("127.0.0.1"); var list = new RedisList<person>(settings, "Person-Key-0"); await list.AddLast(new Person { Name = "AAA", Age = 20 }); await list.AddLast(new Person { Name = "BBB", Age = 35 }); var persons = await list.Range(0, 2);
  25. 25. RedisSettings var settings = new RedisSettings("127.0.0.1"); // 연결할지 않았다면 연결 후 객체를 반환한다. var conn = settings.GetConnection(); 데이터 직렬화 방법 new RedisSettings("127.0.0.1", converter: new JsonRedisValueConverter()); new RedisSettings("127.0.0.1", converter: new ProtoBufRedisValueConverter());
  26. 26. RedisSettings 2개 이상의 redis 서버를 수평 분할로 사용하고 싶을 때 사용한다. // multi group of connections var group = new RedisGroup(groupName: "Cache", settings: new[] { new RedisSettings(host: "100.0.0.1", port: 6379, db: 0), new RedisSettings(host: "105.0.0.1", port: 6379, db: 0), }); // key hashing. key 값으로 어느쪽의 redis 서버를 사용할지 선택할 수 있다. var conn = group.GetSettings("hogehoge-100").GetConnection();
  27. 27. public static RedisGroup redisGroup = null; //var addressList = new List<Tuple<string,int>>(); //addressList.Add(new Tuple<string, int>("172.20.60.208",6379)); //addressList.Add(new Tuple<string, int>("172.20.60.208", 6380)); public static void Init(List<Tuple<string, int>> addressList) { var redisSettings = new RedisSettings[addressList.Count]; for (int i = 0; i < addressList.Count; ++i) { redisSettings[i] = new RedisSettings(host: addressList[i].Item1, port: addressList[i].Item2, db: 0); } redisGroup = new RedisGroup(groupName: "GameServer", settings: redisSettings); } 사례: Redis 샤딩
  28. 28. var list = new CloudStructures.Redis.RedisList<int>(GlobalSettings.Default, "listkey1"); // 모든 값을 지운다. await list.Clear(); // 제일 뒤에 추가 await list.AddLast(1); await list.AddLast(10); // 제일 앞에 추가 await list.AddFirst(100); await list.AddFirst(1000); // 총 갯수 await list.GetLength(); // redis 명령어 중 LRANGE 기능 // 리스트의 0번째부터 시작해서 3개 await list.Range(0, 2); // 1000, 100, 1 사례: list
  29. 29. 사례: hash public class UserAuthInfo { public string ID; public string PW; public string AuthToken; public Int64 UnqiueNumber; } static async Task<UserAuthInfo> GetAccountInfo(string id) { var redisObj = new RedisClass<UserAuthInfo>(MemoryDB.redisGroup, id); var userData = new UserAuthInfo(); userData = await redisObj.GetValue(); return userData; } static void SaveAccountInfo(UserAuthInfo userAuth) { var redisObj = new RedisClass<UserAuthInfo>(MemoryDB.redisGroup, userAuth.ID); redisObj.SetValue(userAuth); }
  30. 30. Configuration <configSections> <section name="cloudStructures" type="CloudStructures.Redis.CloudStructuresConfigurationSection, CloudStructures" /> </configSections> <cloudStructures> <redis> <group name="cache"> <add host="127.0.0.1" /> <add host="127.0.0.2" port="1000" /> </group> <group name="session"> <add host="127.0.0.1" db="2" valueConverter="CloudStructures.Redis.ProtoBufRedisValueConverter, CloudStructures" /> </group> </redis> </cloudStructures> var groups = CloudStructuresConfigurationSection.GetSection().ToRedisGroups()
  31. 31. Redis와 Lua
  32. 32. lua 사용 public async Task<double> IncrementLimitByMin(double value, double min, bool queueJump = false) { using (Monitor.Start(Settings.PerformanceMonitor, Key, CallType)) { var v = Connection.Scripting.Eval(Settings.Db, @" local inc = tonumber(ARGV[1]) local min = tonumber(ARGV[2]) local x = tonumber(redis.call('incrbyfloat', KEYS[1], inc)) if(x < min) then redis.call('set', KEYS[1], min) x = min end return tostring(x)", new[] { Key }, new object[] { value, min }, useCache: true, inferStrings: true, queueJump: queueJump); return double.Parse((string)(await v.ConfigureAwait(false))); } }
  33. 33.  https://code.google.com/p/booksleeve/  http://www.buildinsider.net/small/rediscshap/01  https://github.com/neuecc/CloudStructures 참고

×