제가 닷넷으로 개발할 때, IoC/DI framework 으로 Castle.Windsor 를 사용했습니다. NInject, Spring.NET 등도 있었지만... Castle.Windsor 가 가장 앞서 나갔고, Fluent 방식으로 Component 를 등록하는 것도 지원했습니다.
자바에서는 Spring Framework 이 거의 표준이라서 별 생각없이(?) 잘 쓰고 있습니다. 다만 한가지 아쉬운 점은 같은 Thread Context 별로 다른 Bean (Component) 를 사용하고 싶은데... 할 수 있는 것이라곤...
scope 가 singleton 이거나 prototype 이란 거... 즉 프로세스에 오직 하나의 인스턴스만 있거나, 요청 시 매번 새로운 인스턴스를 준다는 것이지요. 물론 웹에서는 PerSession 등이 있습니다만, 내부 라이브러리에서는 Thread Context 별로 Bean을 제공하는 방식이 추가되었으면 좋겠다 싶었습니다.
Windsor Castle 에는 thread 라고 지정해주면 Thread Context 별로 독립된 인스턴스를 제공해 주거든요^^
그래서 만들어 봤습니다.
우선 Bean 을 정의하는데, 일반적으로 단순 생성해서 주는 게 아니라. TheadLocal을 이용하여, 생성된 인스턴스를 보관하여, 같은 ThreadContext 에서 Bean을 요청하는 경우, 기존 인스턴스를 제공하는 것입니다.
ThreadLocal 에 초기 값을 지정해주고, 필요 시마다 ThreadLocal 의 인스턴스를 제공해 주는 것입니다.
이렇게 하면, Thread Context 별로 다른 인스턴스를 사용하여, 독립적인 작업을 수행할 수 있고, 같은 Thread Context에서는 반복적인 조회에도 같은 인스턴스를 제공할 수 있습니다.
Thread 별로 제공해야 하는 Bean 이 많은 경우에는 위와 같은 작업이 번거로울 수 있습니다. 이럴 때에는 thread 별로 hash map 을 제공하는 것이 좋습니다.
위와 같이 같은 Thread 에서는 하나의 hash map 을 공유하게 되므로, 여러 Class 들간에 인자 전달 방식이 아니더라도, thread 단위로 값을 공유할 수 있습니다.
이렇게 Local 을 이용하여 기존 ThreadLocal 방식을 다시 구현하면
과 같습니다. Bean 마다 ThreadLocal 을 따로 만들지 않아 좋은 장점이 있습니다.
2013년 4월 30일 화요일
2013년 4월 29일 월요일
NIO2 AsynchronousFileChannel 사용 예제
작은 크기의 파일을 읽을 때에는 JDK 1.7 의 Files.readAllLines() 를 사용하면 땡입니다. 하지만 무지 큰 파일을 읽기, 쓰기를 할 경우에는 Disk IO 작업만으로 많은 시간이 걸려, 다른 작업을 못하게 됩니다. 이럴땐 무조건 비동기 작업으로 변환해야 합니다.
왜? 뭐하러? 비동기 작업이 만들기도 어렵고, 버그 발생 시 처리하기도 힘든데...
맞는 말이기도 하지만, 메모리와 CPU에서 처리하는 작업도 비동기 작업으로 처리하는데, 네트웍이나 DISK IO라면 수 천배, 수 만배 느린데, 이것을 비동기로 처리해서, 다른 작업을 처리해 줄 수 있다면 시스템 전체의 작업 효율이 엄청 높아질 것입니다.
Redis 가 초기에 Master/Slave replication 방식을 동기식으로만 지원하다가 비동기 방식도 지원하게 된 이유도 같은 이치라 보시면 됩니다.
자 이제 본격적으로 비동기 방식의 파일 읽기/쓰기를 해보기로 합시다. JDK 1.7 NIO 2 에 보면 기존 NIO 보다 확장되고 향상된 기능이 많습니다.
아직도 JDK 1.7을 쓰지 않는 시스템이나 NIO2 를 쓰지 않는 시스템을 보면 아쉬움이 크네요.
다들 얼른 빨리 업그래이드해서 고성능 기능을 활용하면 좋을텐데 하는 맘입니다.
우선 NIO 2 를 이용하는 방식 중 작은 파일을 다룰 때에는 버퍼링되는 스트림을 사용하는 것이 가장 쉽고, 편합니다.
BufferedReader, BufferedWriter 사용 법은 Files 클래스를 사용하면 끝납니다.
Files.newBufferedWriter, Files.readAllLines 등 내부적으로 BufferedReader, BufferedWriter를 사용합니다. 버퍼링을 통해, DiskIO 작업 횟수를 적게, 한꺼번에 처리하도록합니다.
다음으로는 대용량의 데이터를 파일로 처리할 경우 비동기 방식으로 처리해주는 AsynchronousFileChannel 의 사용법에 대해 보겠습니다. 이름에서 보시다시피 비동기 방식으로 파일의 데이터를 처리합니다.
대용량 데이터를 쓰는 예
데이터를 쓰는 경우도 많은 데이터를 쓰는 동안 다른 일을 처리할 수 있으므로, Future.isDone() 을 검사하여 다른 작업을 처리할 수도 있고, 다른 작업을 처리한 후 Future.get() 을 통해 작업 결과를 알 수 있습니다.
대용량 데이터를 읽는 예
데이터를 읽을 때, isDone() 은 UI 처리 등을 수행할 수 있고, 단순히 get() 으로 기다릴 수도 있습니다.
주의사항 : 테스트 코드라 읽고 난 후 파일을 삭제하게 해 놨으니, 실전에서는 필요에 따라 옵션을 지정해 주세요.
마지막으로 byte[]로 읽어드린 내용이 텍스트라면, List 수형으로 변경해주는 것이 좋겠죠?
라인 처리는 OS 시스템마다 다 다른데, BufferedReader 가 잘 되어 있더군요 ㅋ
자 이렇게 BufferedReader 를 이용하여 작업을 처리했습니다.
왜? 뭐하러? 비동기 작업이 만들기도 어렵고, 버그 발생 시 처리하기도 힘든데...
맞는 말이기도 하지만, 메모리와 CPU에서 처리하는 작업도 비동기 작업으로 처리하는데, 네트웍이나 DISK IO라면 수 천배, 수 만배 느린데, 이것을 비동기로 처리해서, 다른 작업을 처리해 줄 수 있다면 시스템 전체의 작업 효율이 엄청 높아질 것입니다.
Redis 가 초기에 Master/Slave replication 방식을 동기식으로만 지원하다가 비동기 방식도 지원하게 된 이유도 같은 이치라 보시면 됩니다.
자 이제 본격적으로 비동기 방식의 파일 읽기/쓰기를 해보기로 합시다. JDK 1.7 NIO 2 에 보면 기존 NIO 보다 확장되고 향상된 기능이 많습니다.
아직도 JDK 1.7을 쓰지 않는 시스템이나 NIO2 를 쓰지 않는 시스템을 보면 아쉬움이 크네요.
다들 얼른 빨리 업그래이드해서 고성능 기능을 활용하면 좋을텐데 하는 맘입니다.
우선 NIO 2 를 이용하는 방식 중 작은 파일을 다룰 때에는 버퍼링되는 스트림을 사용하는 것이 가장 쉽고, 편합니다.
BufferedReader, BufferedWriter 사용 법은 Files 클래스를 사용하면 끝납니다.
Files.newBufferedWriter, Files.readAllLines 등 내부적으로 BufferedReader, BufferedWriter를 사용합니다. 버퍼링을 통해, DiskIO 작업 횟수를 적게, 한꺼번에 처리하도록합니다.
다음으로는 대용량의 데이터를 파일로 처리할 경우 비동기 방식으로 처리해주는 AsynchronousFileChannel 의 사용법에 대해 보겠습니다. 이름에서 보시다시피 비동기 방식으로 파일의 데이터를 처리합니다.
대용량 데이터를 쓰는 예
데이터를 쓰는 경우도 많은 데이터를 쓰는 동안 다른 일을 처리할 수 있으므로, Future.isDone() 을 검사하여 다른 작업을 처리할 수도 있고, 다른 작업을 처리한 후 Future.get() 을 통해 작업 결과를 알 수 있습니다.
대용량 데이터를 읽는 예
데이터를 읽을 때, isDone() 은 UI 처리 등을 수행할 수 있고, 단순히 get() 으로 기다릴 수도 있습니다.
주의사항 : 테스트 코드라 읽고 난 후 파일을 삭제하게 해 놨으니, 실전에서는 필요에 따라 옵션을 지정해 주세요.
마지막으로 byte[]로 읽어드린 내용이 텍스트라면, List
라인 처리는 OS 시스템마다 다 다른데, BufferedReader 가 잘 되어 있더군요 ㅋ
자 이렇게 BufferedReader 를 이용하여 작업을 처리했습니다.
2013년 4월 18일 목요일
Apache Avro IDL protocol 을 비동기 방식으로 통신하기
연속해서 Avro 에 대해 글을 쓰게 되네요. 이번 프로젝트에 Avro를 사용할 것이고, 팀원들이 쉽게 쓰게 하기 위해서 이 글을 씁니다. ㅋ
Netty 덕분에 Avro 의 통신이 믿을만하고, 속도도 빠르다고 확신합니다만, 개발자 분들도 비동기 방식을 사용하여 더 효과적인 통신이 되도록 하면 좋을 것입니다.
CalculatorServer.java ( 이전 글의 예제를 비동기 방식도 가능하도록 수정)
입니다. 이전 코드에서 변경된 부분은 다음과 같습니다.
변경된 부분만!!!
비동기 방식 통신을 위해서는 Client 를 얻을 때 Calculator.class 를 쓰지 않고, Calculator.Callback.class 를 사용합니다. 이 interface 는 이미 Avro에 의해 생성된 코드입니다.
이를 바탕으로 Callback을 직접 정의해도 되고, CallFuture 를 사용해도 됩니다.
Netty 덕분에 Avro 의 통신이 믿을만하고, 속도도 빠르다고 확신합니다만, 개발자 분들도 비동기 방식을 사용하여 더 효과적인 통신이 되도록 하면 좋을 것입니다.
CalculatorServer.java ( 이전 글의 예제를 비동기 방식도 가능하도록 수정)
입니다. 이전 코드에서 변경된 부분은 다음과 같습니다.
변경된 부분만!!!
비동기 방식 통신을 위해서는 Client 를 얻을 때 Calculator.class 를 쓰지 않고, Calculator.Callback.class 를 사용합니다. 이 interface 는 이미 Avro에 의해 생성된 코드입니다.
이를 바탕으로 Callback을 직접 정의해도 되고, CallFuture
피드 구독하기:
글 (Atom)