In to the C# 2014. 1. 24. 14:23

[C#] Attribute : 속성

Attribute는 속성이나 특성이라는 뜻을 가지고 있습니다.

C#에는 Attribute라는 기능이 있는데, 이것은 클래스나 멤버(메소드/변수)에 Attribute를 지정할 수 있습니다.

Attribute를 지정하는 클래스가 특별히 기능을 하는 것은 아니고, 제 3자가 특정 클래스의 Attribute를 확인해서 어떠한 작업을 처리 하려고 하는 것입니다.

HTML도 속성이 있는 것이 그 자체로 무언가 되는것이 아니라, 브라우저가 파싱해서 보여주고, Javascript가 id로 엘리먼트를 찾을 수 있듯이 말이죠.

 

저는 Attribute를 이용해서 메시지 분배 처리기를 간단하게 구현하였습니다. 보통은 Map이나 Dictionary에 메시지타입과 함수포인터를 연결해놓기 마련인데요. 결과론적으론 제가 구현한 방법도 같은 의미이지만 구현 과정을 보면 코딩의 양을 줄여 줄 수 있는 방법이기도 합니다. 왜냐면 메소드에 Attribute만 지정해주면 되거든요.

 

간단하게 MessageType을 정의 하였습니다.

 

그리고 Attribute 클래스를 정의 하였습니다.

MessageDistributorAttribute 클래스에서도 AttributeUsage Attribute를 사용하는 군요. 메소드에만 MessageDistributorAttribute를 붙일 수 있도록 설정한 것입니다. 그 외엔 Attribute 클래스를 상속한 것 말고는 정말 별다른 것 없는 클래스 입니다.

 

위 소스는 메소드 집합 클래스 입니다.

보통 서버 프로그래밍 할 때 메시지 처리 메소드(함수)의 특징은 파라미터들의 타입과, 리턴 타입이 동일하게끔 설계를 하지요? 이 것도 선조건으로 동일하게 구현해야겠네요. 메소드 구현전에 MessageDistributor라는 Attribute를 추가 해줍니다.

 

아! 클래스 이름은 MessageDistributorAttribute인데 사용할 대는 Attribute를 빼네요? 컴파일러가 알아서 해석합니다. 그냥 그렇게 구현한다고만 기억해두시기 바랍니다.

 

JOIN(가입) - MyMethod1 실행

LOGIN(로그인) - MyMethod2 실행

REQUEST(요청) - MyMethod3 실행

 

이런식으로 되도록 Attribute를 사용 했습니다.

다음은 Main 메소드 입니다.

 

Line 6은 MethodSet 인스턴스에서 타입 정보를 가져 옵니다.

Line 8은 MethodSet 인스턴스에서 메소드 리스트를 가져옵니다.

Line 11은 Method에서 Attribute 배열을 가져옵니다.

Line 16 ~ 18은 Attribute 배열에서 MessageDistributorAttribute 인스턴스를 골라 냅니다.

Line 27은 MethodInfo에서 실행하가능한 Method delegate를 만들어 냅니다.

Line 34 ~ 40 까지는 table에서 MessageType에 따라 메소드를 호출 하는 로직입니다.

Line 43 ~ 55 까지는 MethodSet 인스턴스에서 메소드를 delegate로 뽑아 내는 로직입니다.

 

이런식으로 하면 MessageType이 늘어나고, 처리 Method가 늘어날때마다 table.Add를 줄줄이 써줄 필요는 없게 될 것입니다.

아래는 전체 소스 입니다.

 

아래는 실행 결과 입니다.

조촐하네요;;;

 

 

간단하게 나마 Attribute에 대해서 알아봤는데요.

Attribute는 C#에서 생각보다 많이 사용하게 되니까 알아두시면 좋고, 직접 구현해서 사용하면 성숙한 프로그래머가 된듯한 느낌도 들것 입니다~

'In to the C#' 카테고리의 다른 글

[C#] Task의 작업완료  (2) 2014.01.26
[C#] Action, Func 그리고 Task  (0) 2014.01.26
Lazy Initialization  (0) 2014.01.20
BookSleeve - Pipelined .NET bindings for redis  (0) 2014.01.17
Delegates와 Serialization  (0) 2014.01.17
In to the C# 2014. 1. 20. 18:03

Lazy Initialization

Lazy initialization.

게으른 초기화.

 

네. 초기화를 뒤늣게 하는 것입니다.

가령 인스턴스를 만들 때 인스턴스 멤버들이 초기화 되는데 이 멤버들을 필요한 시점에 초기화 하는 것입니다.

 

Q. 언제 사용하기 위해 이런 개념이 생겨난걸까요?

A. 필드가 많은 경우 사용되지 않는 상황이나 초기화를 빨리하고 부가 작업을 뒤로 미루고 싶을 때 적합합니다.

 

Q. 그럼 언제 사용하지 않는게 좋을까요?

A. 최적화를 통해 성능 저하를 해결해야 하는 상황이 아니라면 초기화의 지연을 사용하지 않아야 합니다. 어떤 경우에는 이런 기법이 디버깅을 어렵게 만듭니다.

 

위 소스 예제는 C#에서의 Lazy 클래스를 설명해줍니다.

 

Line 17과 같이 객체를 생성하여도 LazyList는 값이 생성되지 않은 상태 입니다.

Line 19와 같이 값을 참조 하기만 하여도 LazyList는 생성이 됩니다. Lazy 객체의 Value는 읽기 전용이라 바로 값을 쓰지 못합니다. 소스와 같이 값을 참조한 다음에 활용하여야 합니다.

 

Line 25와 같이 Test 객체에 List가 채워진걸 보실 수 있습니다.

 

이 Lazy객체는 생각보다 빠르지 않습니다. 퍼포먼스가 떨어집니다. 그러므로 가능한 사용하지 않고, 첫번째 질문처럼 해당 사항이 발생하지 않을 때에는 사용하지 않는 편이 좋습니다.

 

C#에서 Lazy initialization의 대표적인게 LINQ에서 사용이 되는데요. LINQ에 대해 제대로 모르면 심각하게 삽질을 할 수 있는 경우가 생깁니다.

아래 소스를 먼저 보시겠습니다.

 

 

위 소스를 보시면 Line 15는 MyList의 요소를 꺼내요 factor를 곱한 뒤 selected에 넣는 그런 내용입니다.

그런데 Line 17에서 factor를 20으로 변경해주었군요.

 

Line 21에서 linq의 결과물을 프린트 하고 있습니다.

결과는 아래..

 

 

 

네. 의도한 바와 같이 10이 곱해진게 아니라 20이 곱해졌습니다.

위의 코드에선 정확히 selected.ToList()를 할 때, 결과가 정해지게 되어 있습니다.

 

이런 점을 유의 하여 코드를 작성할 수 있도록 해야 합니다.

 

끝~

'In to the C#' 카테고리의 다른 글

[C#] Action, Func 그리고 Task  (0) 2014.01.26
[C#] Attribute : 속성  (0) 2014.01.24
BookSleeve - Pipelined .NET bindings for redis  (0) 2014.01.17
Delegates와 Serialization  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
ASP.NET 2014. 1. 19. 14:34

ASP.NET SignalR self hosting 구현

SignalR을 이용한 채팅서버 구현하기에서는 서버를 IIS 호스팅 하였습니다. 그러나 굳이 IIS호스팅 할 필요없이 독립적인 자기 호스팅으로 서버를 실행할 수 있습니다. 총 50라인도 안되는 코드로 말이죠. 참고로 이방법은 Web base 방식이 아니어서 저번 처럼 웹페이지 채팅이 불가능합니다. 이 경우 추가 웹 프로젝트를 만들어 주어야 합니다.


가장 먼저 콘솔 어플리케이션 프로젝트를 생성하여 줍니다. 

그리고 SignalR 라이브러리를 패키지 관리자 콜솔을 통해서 설치하여 줍니다.


PM> install-package microsoft.aspnet.signalr.selfhost

PM> Install-Package Microsoft.Owin.Cors


이제 코딩만 하면 됩니다. 

Line22 ~ 29 처럼 먼저 Startup을 만들어 줍니다. Startup은 지난번에도 설명하였듯이 클라이언트와 서버의 접속점을 만들어 주는 역할을 합니다.


Line 31 ~ 38는 ChatHub입니다. 기존에 했던 것과 다를바 없습니다.


Line 12 ~ 19처럼 main 메소드를 구현합니다. uri에서 http://localhost:8080/으로 정의 하였는데, 만약 모든 host에 바인딩을 시켜주려면 uri를 http://*:8080 을 입력해주면 됩니다.


절대참고!

uri가 localhost가 아닐경우 TargetInvocationException 에러가 발생합니다. 이럴 경우 Visual Studio를 관리자 권한으로 재실행 하여야 합니다.


여기까지 구현하면 서비스를 이용할 수 있습니다.


여기에 웹페이지를 추가하여 웹과 Native간 통신이 가능하도록 해보겠습니다.


솔루션 -> 추가 -> 새 프로젝트 -> ASP.NET 빈 웹응용 프로그램을 합니다. 그리고 패키지 관리자 콘솔에서 기본 프로젝트를 새로 추가한 웹프로젝트로 선택 후 아래와 같이 커맨드를 입력합니다.


PM> Install-Package Microsoft.AspNet.SignalR.JS


그리고 index.html을 추가하구요. 소스를 아래와 같이 작성합니다.


기존과 다른점은 Line 24와 Line 28입니다. 

SelfHosting server를 실행하고 html에 접속하면 self hosting된 서버에 접근하게 됩니다. 




위 캡쳐 화면과 같이 좌측 상단은 서버입니다.

좌측 하단은 SignalR 서비스를 이용하는 native client이구요. 우측 하단은 웹페이지 클라이언트입니다.

이렇게 self hostring하는 방법을 구현 해보았습니다.

ASP.NET 2014. 1. 19. 00:38

SignalR을 이용한 웹과 네이티브 어플리케이션간 채팅 구현

몇일 전 부터 SignalR에 꽂혀서 조금씩 공부를 하기 시작 했습니다.

좀 아쉬운 점은 서버를 구현하기 위해서는 닷넷 프레임워크 4.5 이상이 되어야 합니다. 즉, Visual Studio2012이상에서 개발 하셔야 합니다. 2014년도 인데 이제 갈아 탈만도 하죠; 회사에서 아직까지 2010을 사용하는 제가 구식일지도;;


1. 서버 구현하기

Step by step으로 구현하겠습니다.


빈 웹 프로젝트를 만들어 줍니다.

첫째로 nuget으로 SignalR을 검색해서 패키지를 추가해 줍니다.

nuget이 없으시다면 설치를 추천드립니다. 만약 하기 싫으시다면 도구 -> 라이브러리 패키지 관리자 -> 패키지 과리자 콘솔 로 들어가 install-package Microsoft.AspNet.SignalR 을 실행합니다.

여기까지 정상적으로 완료가 되면 SignalR관련 라이브러리와 자바스크립트 파일들이 설치가 됩니다.


두번째로 Startup을 구현해줍니다. Startup은 클라이언트와 서버의 접속점을 설정해주는 역할을 합니다.

솔루션 탐색기 -> 프로젝트 에서 오른쪽버튼 -> 추가 -> 클래스 실행합니다. Startup.cs파일을 만들고 아래와 같이 구현해줍니다.


보시면 아시겠지만 그리 복잡하지 않습니다.

정확히 내부 로직이 어떻게 되는지는 몰라 설명을 못드려 죄송합니다.


다음은 메시지를 받아서 모든 유저들에게 전송하는 Method를 구현하겠습니다. 

솔루션 탐색기 -> 프로젝트에서 오른쪽 버튼 -> 추가 -> 클래스 실행합니다. ChatHub.cs파일을 만들고 아래와 같이 구현합니다.


클래스 선언부에 HubName Attribute를 추가해줍니다. 이 HubName을 외부에서 이 메소드를 찾아가는데 필요한 역할을 해줍니다.

Line 15 에서 Clients는 서버에 접속한 모든 ClientContext들의 모음 입니다. All은 모든 Client를 의미하고 인텔리센스로 검색해보면 Caller라고도 나옵니다. Caller는 의미대로 메시지를 보낸 유저를 의미합니다. 위의 소스는 채팅을 받아서 모두에게 보내는 것입니다. 


2. 웹페이지 구현하기

이제 웹페이지를 구현해보겠습니다.

술루션 탐색기 -> 프로젝트에서 오른쪽 버튼 -> html 페이지 추가 실행합니다. index.html을 추가하고 파일의 오른쪽 버튼을 클릭하여 시작페이지로 설정합니다. 그리고 페이지를 아래와 같이 구현합니다.


SignalR을 설치하면 아마도 Visual Studio 버전에 따라 서로 다른 jquery파일이 설치 될 수도 있습니다. Line 22 ~ 23은 설치된 jquery파일을 잘 확인하시고 적어줍니다. 


Line 24는 서버 실행시 SignalR이 스크립트 파일을 만들어 줍니다.


Line 28은 허브에 연결합니다. $.connection.Chat에서 Chat은 ChatHub.cs에 HubName 기억하시죠? 바로 그 HubName으로 해당 클래스를 찾아갑니다.


ChatHub.cs의 Clients.All.broadcastMessage를 호출하면 자바스크립트에서 Line 29의 broadcastMessage가 호출이 됩니다. 즉, 서버에서 클라이언트 메소드를 호출하는 것이죠.


Line 40은 허브 연결이 끝나면 그 아래 코드를 호출하는데 sendmessage를 클릭하면 이름과 메시지가 전송됩니다. 


Line 42의 send는 ChatHub의 Send메소드를 호출하는 코드입니다. 자바스크립트에서 send를 Send로 바꿔서 해보니까 잘 안되었습니다. 소문자로 작성을 하지 서버 메소드가 호출이 잘되는데...그이유를 잘 모르겠습니다.


이렇게 서버의 작업은 모두 끝났으며, F5를 눌러 실행합니다. 

테스트로 Hello라는 텍스트를 입력하고 보냈습니다. 화면에 보여지는 Hello는 서버를 거쳐서 돌아 온 것입니다.


3. Native Application 구현하기

SignalR의 장점은 라이브러리만 잘 활용하면 Native Application에서도 작동합니다. 현재 서버를 IIS서비스로 호스팅을 하고 있지만 독자적인 호스팅도 가능합니다. 이 부분은 다음에 구현해보도록 하겠습니다.

SignalR 클라이언트는 닷넷 프레임워크, iOS, MONO로 구현이 가능하다고 합니다. 추후에는 C++에서도 가능하도록 구현중이며, 아마 자바도 나오지 않을까 싶네요.

콘솔응용 프로그램을 하나 만들어 줍니다. 

그리고 signalr.client를 설치 합니다. 서버와 마찬가지로 nuget에서 검색하거나, 패키지 관리자 콘솔에서 아래와 같이 입력하여 설치합니다.


PM > install-package Microsoft.AspNet.Signalr.client


client 소스가 길지 않으니 먼저 보겠습니다.



Line 14는 서비스 Url을 입력하여 새로운 커넥션을 만들어 줍니다.


Line 15는 HubName을 이용하여 proxy를 생성해 줍니다. HubName은 서버 소스와 마찬가지로 "Chat"이었죠.


Line 16은 Hub연결을 시작하고 연결될때까지 기다립니다. 주의할점은 proxy부터 생성하고 hub연결을 해야 합니다. 그렇지 않으면 오류가 발생합니다.


Line 17은 서버가 수행하는 broadcastMessage라는 클라이언트 메소드를 정의 한 것입니다.


Line 24는 proxy를 통해서 Send라는 서버 메소드를 실행하는 것입니다. 이렇게 준비는 끝났으며, 웹페이지와 네이티브간 채팅을 캡쳐하였습니다.

이렇게 SignalR을 통해서 채팅서버를 구현하였습니다. 

ASP.NET 2014. 1. 18. 01:10

ASP.NET SignalR을 이용한 실시간 양방향 커뮤니케이션 구현

양방향 커뮤니케이션의 새로운 가능성을 보여주는 SignalR입니다. 웹서버 호스팅에서만 되는게 아니라 독립적인 호스팅으로도 서비스가 가능하다는데요. 퍼포먼스 측면에서는 아직 설명이 없지만 충분히 매력적인 기술임에는 틀림 없고, 발표자 말씀과 같이 다양한 곳에 충분히 사용하여도 무방하리만큼 쉽고, 강력합니다.

특히 SQL Server를 이용한 Scale Out은..머..엄청나네요;


1부


2부


출처 : 

http://channel9.msdn.com/Events/TechDays/TechDays-2013-Korea/SignalR-1-2-

http://channel9.msdn.com/Events/TechDays/TechDays-2013-Korea/SignalR-2-2-

In to the C# 2014. 1. 17. 16:56

BookSleeve - Pipelined .NET bindings for redis

Redis

key-value 저장을 위한 메모리 서버로 string, hash, list, set, sorted set을 지원합니다.

Redis는 BSD 라이센스가 있는 오픈소스이며, windows용 서버는 정식 지원하지 않고 있습니다.

다만 windows에서 돌릴 수 있도록 비공식 프로젝트가 있긴 합니다.

https://github.com/MSOpenTech/redis


C#에서도 Redis client를 위한 다양한 라이브러리들이 존재합니다.

그런데 여기선 가장 쓰기 쉬운 라이브러리 BookSleeve를 소개하려 합니다.


BookSleeve의 장점은 세가지가 있습니다.


  1. 스레드로 부터 안전함.
    BookSleeve는 하나의 커넥션만으로 여러개의 스레드에서 동시 접근을 하여도 안전성을 보장 합니다.

  2. 비동기 처리
    BookSleeve는 모든 커맨드가 Task를 리턴하게 됩니다. 즉, 내부적으로 blocking되지 않고, 넘어갑니다. 이것은 여러개의 커맨드를 동시에 수행하고 한번에 동기화 할 수 있습니다.

  3. 사용이 쉽다
    네 사용이 너무 쉽습니다. 도큐먼트 찾기가 어려워서 그렇지 조금만 알면 금방 합니다.


위 소스는 byte[] 입출력 / sorted set 사용법 / publish, subscribe 사용법에 대한 내용이 포함되어져 있습니다.


Line 22 ~ 24는 string을 byte[]로 변환한 뒤 Redis에 저장 / 읽기를 보여주고 있습니다. “Park”은 key이며, “string test”는 value입니다. 참고로 Line 24에서 result.Result를 하게 되면 비동기화 작업 result가 종료될 때까지 기다린다음 Result값을 가져옵니다. 즉, 굳이 result.Wait()를 할 필요가 없다는 뜻입니다.


Line 27 ~ 28은 sorted set에 값을 넣습니다. “mySet”은 set key이며, “Kwon”은 value, 99는 score입니다. sorted set은 score의 값에 따라 정렬을 하며, 가장 작은 score는 rank가 0이 됩니다. rank를 역순으로 구할 수도 있습니다. Line 35 ~ 36이 역순으로 rank를 구한 다음 화면에 rank를 출력합니다. Rank 메소드 true면 올림차순, false이면 내림차순 입니다.


Line 39 ~ 40은 value가 없을 때 요청을 하면 어떻게 나오는지 알려줍니다. “mySet”에는 “Bong”이라는 value가 없으며, 결국 rank값은 null이 되어서 return 되었습니다.


Redis는 Publish/Subscribe가 있습니다. 여러 클라이언트간 채널을 통해 메시지를 주고 받을 수가 있습니다. Line 43 ~ Line 58이 그 예제를 보여주고 있습니다. 

Line 43은 먼저 Subscribe채널을 얻어옵니다. 채널로 메시지가 오면 처리할 대리자 Action<string, byte[]>를 정의 하구요. 채널 이름과 대리자를 등록합니다. subConn.Subscribe(“channel1”, action);

Line 54는 패턴구독을 정의 한 것입니다. “cha*”라고 채널명을 입력하였습니다. cha로 시작하는 채널명에 Publish가 되는 것이 있으면 모두 받아온다는 의미 입니다. 

Line 58은 “channel1”이라는 채널로 “Publish!!”라는 string을 publish 하였습니다. 그러면, 이미 등록된 대리자 action으로부터 메시지를 받아 올 수 있습니다.


여기서 대리자를 보면 알 수 있듯이 byte[] 배열의 데이터가 넘어옵니다. 즉, 보낼 때도 string이 아닌 byte[] 배열로 보낼 수도 있습니다.

이것을 활용하면 서버간 메시지 송수신 역할의 서버로도 활용할 수가 있습니다.


위 소스의 실행결과는 아래와 같습니다. 




'In to the C#' 카테고리의 다른 글

[C#] Attribute : 속성  (0) 2014.01.24
Lazy Initialization  (0) 2014.01.20
Delegates와 Serialization  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
Thread Pool과 Task  (0) 2014.01.14
In to the C# 2014. 1. 17. 14:32

Delegates와 Serialization

C#에서 클래스를 직렬화 하는 것은 매우 쉽습니다.

클래스 선언 전에 [Serializable] attribute만 추가 해주면 아주 멋지고 쉽게 직렬화가 가능합니다.


그런데 아래와 같은 delegates(이하 대리자)가 멤버로 있을 때 문제가 될 수 있습니다.



예제는 Action이 있는데요. C#의 대표적인 대리자가 있습니다. 대리자도 하나의 객체 이기 때문에 위와 같이 클래스를 선언하고 인스턴스를 직렬화 하게 되면 대리자도 같이 직렬화가 됩니다.


여기서 중요한건 역직렬화 할 때 잘 될 수도 있고, Exception 에러가 날 수도 있습니다. 대리자를 직렬화 하는건 매우 어려우며, 하더라도 내부의 타겟 객체의 모든 것을 제대로 직렬화 하는걸 보장 하지 않기 때문입니다.

결론적으로 대리자는 직렬화 대상에서 빼야 하며 설계 시 아래와 같이 해주어야 합니다. 개발자가 어떻게 직렬화 할 수 있는 문제가 아닙니다!!



Protobuf-net에서는 Protomember로 선언을 하여도 직렬화 대상이 되질 않으며, 역직렬화 시 null 값이 채워집니다.

'In to the C#' 카테고리의 다른 글

Lazy Initialization  (0) 2014.01.20
BookSleeve - Pipelined .NET bindings for redis  (0) 2014.01.17
Dispose in C#  (0) 2014.01.14
Thread Pool과 Task  (0) 2014.01.14
Google Protocol Buffer 사용해보기 with C# - 세번째  (0) 2014.01.14
db 2014. 1. 15. 11:09

NoSQL 알기

NoSQL 정의


NoSQL Not Only SQL, 또는 No SQL로 많이 알려져 있습니다. 그러나 공식적으로 정의된 적이 없으며, NoSQL이란 단어는 영국 소프트웨어 개발자 Johan Oskarsson이 오픈소스 분산 데이터베이스의 토론을 위해 주관한 모임의 이름에서 유래 됐다고 합니다.

마틴파울러는 NoSQL이 아래의 조건을 만족하는 데이터 저장소라고 기술 하였습니다.


1.     대용량 웹 서비스를 위하여 만들어진 데이터 저장소

2.     관계형 데이터 모델을 지양하며 대량의 분산된 데이터를 저장하고 조회하는데 특화된 저장소

3.     스키마 없이 사용 가능하거나 느슨한 스키마를 제공하는 저장소

 

, NoSQL이란 빅데이터를 처리하기 위한 분산 데이터 저장소의 통칭 정도로 이해하면 쉽습니다.

 

CAP


CAP란 컴퓨터 과학 분야에서 분산 컴퓨터 시스템을 설명하는데 사용되는 이론입니다. 이론의 뜻은 “Consistency(일관성), Availability(가용성), Partition Tolerance(분할 허용성) 모두를 동시에 지원하는 분산 컴퓨터 시스템은 없다라고 정의 되어 있습니다.


Consistency(일관성) : 동시성, 동일성이라고도 하며, 다중 클라이언트에서 같은 시간에 조회하는 데이터는 항상 동일한 데이터임을 보증하는 것을 의미합니다. 즉, 어떤 값이 바뀌면 바뀌기 전의 데이터가 노출되면 안된다는 의미 입니다. 일관성은 RDBMS에서 지원하는 가장 기본적인 기능입니다. 그러나 NoSQL에서는 빠른 분산 처리를 위해 일관성을 희생하기도 합니다.

 

Availability(가용성) : 모든 클라이언트의 읽기와 쓰기 요청에 대하여 항상 응답이 가능해야 함을 보증하는 것을 의미 합니다. NoSQL은 클러스터 내에서 몇 개의 노드가 망가지더라도 다른 노드가 값을 가지고 있어 클라이언트 요청에 대한 응답을 반드시 할 수가 있습니다.

 

Partition Tolerance(분할 허용성) : 지역적으로 분할된 네트워크 환경에서 동작하는 시스템있습니다.. 두지역 간의 네트워크가 단절되거나 네트워크 데이터의 유실이 일어나더라도, 각 지역 내의 시스템은 정상적으로 동작해야 함을 의미 합니다.

 

분산컴퓨터 시스템에서 CAP중 두가지만 지원하는게 아니라 두가지를 지원하기 위해 한가지를 희생하는 것입니다. 이 이론은 2000년 전산학자 에릭 브루어가 가설을 제시하고, 2002년 세스 길버트와 낸시 린치가 증명하였습니다.


사진출처 : http://blog.nahurst.com/visual-guide-to-nosql-systems


CA : RDBMSs, 애스터 데이터, 그린플럼, 버티카

CP : 빅테이블, 하이퍼테이블, HBASE, MongoDB, 테라스토어, 스칼라리스, 버클리DB, 맴캐시DB, 레디스

AP : 다이나모DB, 카산드라, 볼드모트, 도쿄캐비닛, KAI, 심플DB, CouchDB, 리악

CAP 이론으로 나눈 NoSQL.


 

NoSQL의 저장방식


1.     -값 모델 형식 : 레디스, 리악, 다이나모, 볼드모트 등이 키-값 구조로 데이터를 저장합니다-값 모델은 단일키 처리만을 지원하기 때문에 복잡한 다중연산이 필요한 서비스나 값 기준 검색이 지원이 필요한 서비스에는 어울리지 않습니다.


2.     문서 모델 형식 : MongoDB, CoushBase, 테라스토어, 레이븐DB 등이 문서모델로 저장이 됩니다. 문서 모델 NoSQL의 키는 문서에 대한 ID로 표현이 됩니다. 또한 저장된 문서를 컬렉션으로 관리하며, 문서 저장과 동시에 문서 ID에 대한 인덱스를 생성합니다. 이 인덱스를 통해 O(1)의 시간안에 문서를 조회할 수 있습니다. 문서 모델은 관계형 데이터베이스와 유사한 검색 조건을 포함한 쿼리를 처리할 수 있있습니다. 그리고 B트리의 특성으로 인하여 한번 작성되면 자주 변하지 않는 정보를 저장하고 조회하는데 적합합니다. 예를들어 로그 저장, 타임라인 저장, 통계정보 저장등이 해당됩니다.


3.     컬럼 모델 형식 : HBASE, 카산드라, 하이퍼테이블이 이에 해당됩니다. 1 map(또는 Dictionary)와 비슷하고, 2 json, bson등의 구조를 상상하시면 편하지만 컬럼 모델 형식은 조금은 생소한 방법입니다. 컬럼은 컬럼 이름, 컬럼 값, 타임스탬프로 구성이 되어져 있으며, 컬럼의 집합은 row이고 row key는 각 row를 식별하는 값이 됩니다. row의 집합은 테이블 또는 키 스페이스가 됩니다. 몇가지 컬럼들을 묶어 컬럼 패밀리를 구성할 수도 있습니다. 컬럼 패밀리는 디스크 저장방법에 영향을 줍니다. 타임 스탬프란 값에 대한 버전이라고 이해하면 됩니다. user1 이란 row key score라는 컬럼이 있습니다. score 50, 60, 70을 입력하면 score라는 이름의 컬럼이 3개가 되며, 각각 입력된 타임스탬프를 갖고 있습니다. 이때 값을 요청하게 되면 최근 타임스탬프의 값을 돌려주며, DB설정에는 컬럼의 유지 개수를 설정할 수도 있으며, 과거의 데이터도 조회할 수 있습니다. 컴럼 모델 형식은 느슨한 스키마를 제공합니다. 데이터를 저장하려면 테이블과 컬럼 패밀리를 미리 생성해주어야 합니다. -값 모델과, 문서 모델은 스키마 없이 사용이 가능합니다. 타임스탬프라는 역할로 데이터 업데이트가 없으며, 항상 INSERT만 있습니다. 컬럼 모델형식은 쓰기에 가장 특화가 되어 있습니다. 채팅내용이나 메일 저장소, 알림내용 저장, 실시간 분석을 위한 데이터 저장소 등의 서비스 구현에 적합합니다. 카산드라는 페이스북에서 메일과 쪽지 알림을 처리하기 위해 개발 하였습니다.


4.     그래프 모델 : 그래프 모델은 알려진 DB로는 Neo4J, OrientDB, HypergraphDB, Infinite Graph등이 있습니다. 그래프 모델은 노드와 관계로 이루어 지는데, 관계는 조회조건으로 사용되며, 방향성이 있습니다. 관계로 조회를 하다보면 결국 어마어마한 순회가 될 수도 있어 순회의 깊이를 제한하기도 합니다. 그래프 모델은 연관검색이나 친구추천, 내 친구가 좋아하는 영화 추천받기등에 활용할 수가 있습니다. Neo4J의 경우 Shard를 지원하지 않으며, 모든 데이터가 단일 서버에 존재해야 한다는 점이 있어 빅데이터와 어울리지 않는다는 의견도 있습니다.

 

당신의 선택은?


요즘 같은 시대에 기획자들의 컨텐츠를 따라가려면 한가지 DB를 사용하기에는 커다란 무리가 있습니다. 적어도 2, 3개의 DB를 가져가야 되죠. 게임을 개발하는데에 한 종류의 DB로 모든 것이 구현 가능해도 서비스에 문제가 발생할 것입니다. 기본 데이터는 RDBMS에 저장하고, 빠른 캐시성 대이터 읽고쓰기/정렬을 위해서는 Redis를 쓰고, 로그는 스키마에서 자유로운 MongoDB를 쓰는 등 적절한 곳에 DB등을 사용하여야 몸도, 마음도 편해질 것 같습니다.

 

결론


열심히 공부하자.


도움 책 : 이것이 레디스다 - 정경석 지음


hello world 2014. 1. 14. 18:56

Google Protocol Buffer 사용해보기 - 개정판

저번에 너무 대충 쓴거 같아서 차근차근 해볼수 있도록 다시 올려봅니다.


우선 소스를 받습니다. ( https://code.google.com/p/protobuf/ )

까보면 대충 폴더가 이렇습니다.


vsproject 폴더에서 protobuf.sln 파일을 찾아서 visual studio 같은걸로 빌드해줍니다.


debug 나 release 든 폴더에 protoc.exe 파일이 생성됩니다. 이걸로 .proto 파일을 .h 와 .cc 로 만들어 주게 됩니다.

 
message Person {
    required string name = 1;
    required int32  id = 2;
    optional string email = 3;
 
    enum PhoneType {
      MOBILE = 0;
      HOME = 1;
      WORK = 2;
    }

    message PhoneNumber { 
        required string number = 1;
        optional PhoneType type = 2 [ default = HOME ];
    }
    repeated PhoneNumber phone = 4;
}


옵션을 잘 골라서 이전에 만든 proto 파일을 잘 역어주면... pb.cc 파일 과 pb.h 파일이 생성 됩니다.

protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/test.proto

이라고 tutorial page 에 되어있습니다만 저는 .bat 파일 만들어서 실행하고 있습니다.

del .\output\*.h

del .\output\*.cc

for %%a in (*.proto) do protoc.exe -I=. -I=../../protobuf-2.5.0/src --cpp_out=./output/ %%a

pause

사용할 때는 Directory 와 lib 파일을 설정해야 합니다.

1. Include path : protobug-2.5.0/src


 2. library path : 아까 build한  output 폴더 


 3. library file : libprotobuf.lib



이제 사용할 일만 남았어요


myfile 이라는 파일에 fstream 을 이용해서 저장하고, 다시 파일에서 일거와서 메모리에 가져와서 출력해 보겠습니다.


우선 include 부터 하고

 #include "test.pb.h" 


쓰기.

Person person;                      // proto 에서 저장한 객체를 사용 할 수 있습니다.
person.set_name("John Doe");        // 기본적으로 set_이름, get_이름 을 사용할 수 있습니다.
person.set_id(1234);
person.set_email("123@test.com");

fstream _output( "myfile", ios::out | ios::binary);   
person.SerializeToOstream(&_output);        // myfile 이란 파일에 바로 써버립니다.
_output.close();


읽기.

fstream input( "myfile", ios::in | ios::binary );  // myfile 이란 파일에서 읽습니다.
Person personReadMsg;
PersonReadMsg.ParseFromIstream(&input);
cout << "Name: " << personReadMsg.name() << endl 
       << "Email : " << personReadMsg.email() << endl;


결과 .



간단하게는 이렇게 써볼 수 있습니다.

실제로는 SerializeToString 이라던지 SerializeToArray 함수를 이용해서 소켓 버퍼에 써서 통신하고 있습니다.


한가지 특이한 점?은 동적으로 스키마를 만들 수 있습니다.

DynamicMessageFactory 를 찾아 보시면 됩니다. - 나중에 시간되면 알아보는걸로..


이걸가지고 뭘 하냐면, 클라이언트에서는 proto 파일을 갖고 있지않고, 서버에서 보내준 스키마를 사용합니다.

서버로 부터 받은 스키마를 통해 xml 로 Parsing 해서 가공해서 사용하고 있습니다.


ps : 저번에 쓴글에 오류가 많아서 다시한번 protobuf 에 대해서 써봤습니다. 지난글은 잊어주세요 ㅋㅋㅋ

In to the C# 2014. 1. 14. 16:17

Dispose in C#

C#은 Garbage Collector에 의해 Heap메모리를 관리하고 있습니다.

C나 C++ 처럼 메모리 해제를 프로그래머가 대신 해줄 수는 없습니다. 구글에 C#에서 인스턴스 해제를 어떻게 하냐는 질문에는 Dispose를 구현하라 라고 나와있는 글들이 많습니다.


그러나 Dispose패턴은 메모리 해제와 관련이 없습니다. Dispose의 정보가 상당히 와전된 경우 입니다. 저도 그렇게 알고 있었는데 다시 찾아보니 그게 아니더군요.


Dispose의 사전전 의미로는 처분하다/처리하다/폐기하다 라는 뜻으로 왠지 메모리 해제와도 관련이 있어 보이긴 합니다.


이제 자세히 알아보겠습니다.

Dispose의 구현은 대게 Close나 Dispose 멤버 메소드를 갖고 있는 인스턴스를 멤버로 갖고 있을 때 구현해주어야 합니다. 즉, 런타임중 관리되지 않는 핸들, 데이터베이스 연결등 리소스에 대한 제어를 명시적으로 해주기 위함입니다. (Finalize 구현으로 암시적으로 수행할 수도 있습니다.)


명시적으로 리소스를 정리하기 위해서는 Dispose를 구현하여야 합니다. 예제를 보겠습니다.


DisposeableObject는 Stream을 멤버로 보유하고 있습니다. 우리는 DisposeableObject를 다 쓴 경우 Stream의 핸들을 해제 시켜주어야 합니다. 그래서 명시적으로 DisposeableObject는 Dispose를 구현하도록 만들어 준 것입니다. 


그리고 Line 43에 보면 GC.SuppressFinalize를 호출합니다. 이것은 Finalize가 호출 되지 않도록 막은 것입니다. MSDN에서는 GC.SuppressFinalize를 호출하기를 권장합니다. 단, Finalize에서 호출되어야 하는 패턴이 존재한다면 이 규칙은 적용되지 않습니다. 

DisposeableObject를 다 사용한 경우 Dispose 메소드를 호출하는 것이 가장 이상적입니다.


위 내용을 요약하면 멤버 객체중에 Close, Dispose메소드를 갖고 있는 경우 Dispose를 구현하라는 내용입니다. 


추가  : Close와 Dispose의 개념적 차이

한줄로 표현한다면 Close된 객체는 재사용이 가능하고, Dispose된 객체는 재사용이 불가능 하다고 생각하면 됩니다. 단 Close에서 Dispose를 호출한다면 이또한 사용할 수 없겠죠.


추가2 : 그럼 메모리 해제는?

Garbage Collector가 알아서 잘할테니 건드리지 마세요.