기본 콘텐츠로 건너뛰기

4월, 2016의 게시물 표시

[펌요약] 자바의 Adapter, Decorator, Façade, Proxy 패턴의 유사점과 차이점

Adapter vs Decorator vs Facade vs Proxy Design Pattern in Java 관련 글이 있어서 간단하게 요약.

Adapter, Decorator, Façade, Proxy 패턴의 유사점은 Composition과 Delegation.
Adapter패턴은 interface를 감싸서 호출을 위임. Decorator는 object를 감싼 동작을 구현. Façade는 하나 이상의 interface를 감싸고 사용하기 쉬운 중앙 집중된 interface를 제공. Proxy는 Subject를 감싸고 호출을 위임. 
그.런.데!! 왜 이것들이 다른 패턴인가?! 만약 같은 구조라면, Adapter, Decorator, Façade, Proxy 패턴의 다른 점은 무엇인가? 답은 Intent다.

Adapter 패턴의 주된 목적은 interface 전환(convert)이다. Adapter는 두 개의 컴포넌트가 같이 동작하게 한다. 두 개가 같이 동작하지 않는 것은 두 컴포넌트의 interface가 맞지 않기(incompatible) 때문이다.
Decorator 패턴은 실행 시점에 새로운 기능을 추가한다. 심지어 생성 후에도 object의 기능을 추가할 수 있게(enrich) 한다.

Façade 패턴은 interface 전환도 새로운 기능추가도 아니다. 대신에 간단한 interface를 제공해서 클라이언트가 직접 시스템 내부의 개별 컴포넌트에 접근하게 하는 대신에 Façade를 사용하게 한다.

Proxy 패턴은 Adapter와 Decorator와 아주 비슷하지만, object 접근제어가 목적이다. Proxy는 클라이언트의 직접적인 접근을 막는 대신, 실제 object처럼 동작한다. 그리고 실제 object처럼 동작하고 다른 행동을 하거나 원래 object에 요청을 보낼 수도 있다. Proxy는 이 모든 패턴 중에서 가장 다목적한 패턴이고, 다른 방법으로 사용될 수 있다. 예를 들어, 원격 object와 통신하는 Remote proxy, 비용이 많이 드는 ob…

카프카 컨슈머 설정

컨슈머 설정은 config/consumer.properties에서

컨슈머 기본세팅
group.id 단일 그룹으로 컨슈머 그룹을 구분하는 문자열값. 같은 ID를 지정하면 동일한 그룹으로 마킹 할 수 있다.

zookeeper.connect브로커 설정 참고

consumer.id컨슈머 ID가 지정되지 않으면 자동 생성된다.

스레드와 성능설정
socket.receive.buffer.bytes 네트워크 요청에 대한 받기 버퍼의 크기. 기본 1024000.

fetch.message.max.bytes 요청이 있을 때 마다 토픽의 파티션에서 패치 할 바이트 수. 프로듀서가 설정값 보다 큰 값을 보내는 경우는 메시지를 받을 수 없기 때문에, 프로듀서가 보내는 최대 메시지 만큼 값이 커야 한다. 또한, 컨슈머가 패치한 메시지를 메모리에 유지하기 때문에 사용하는 만큼 메모리 설정도 해야 한다. 이 값은 주의 깊게 설정되어야 하는 값이다. 기본 1024 * 1024

num.consumer.fetchers 카프크에서 데이터를 패치할 때 사용될 스레드 개수. 기본 1

queued.max.message.chunks 소비되기 전에 버퍼될 수 있는 최대 청크수. 청크는 최대 fetch.message.max.bytes 만큼 크기가 될 수 있다. 기본 2

fetch.min.bytes 서버에서 패치될 최소 바이트 수. 요청을 응답하기 전에 더 많은 데이터가 패치 될 때 까지 기다린다.

consumer.timeout.ms 만약 메시지를 소비할 상황이 되지 못한다면 예외를 던지는데, 예외를 던지기전 컨슈머 스레드가 기다릴 시간. 기본 -1


로그 세팅
auto.commit.enable true 일경우, 컨슈머는 실패할 경우에 복구하기 위해 메시지 오프셋을 저장한다.

rebalance.max.retries 컨슈머 그룹에서 파티션 수가 동일하게 분산된다. 만약 새로운 컨슈머가 조인하면,  파티션 할당을 재조정 한다. 파티션 수를 재조정 하는 동안 그룹에 변경이 생기면, 새 컨슈머에 파티션을 할당하는 작업…

카프카 프로듀서(Producer) 0.9.0 설정

프로듀서 설정은 config/producer.properties 파일에서..

bootstrap.servers  호스트/포트 쌍으로 된 리스트로 카프카 초기에 클러스터에 연결할 때 사용한다. 이 리스트는 단순히 처음에 전체 서버를 찾는데 사용되는 호스트 리스트다 - host1:post1,host2:port2.. 형식 전체 클러스터 멤버(클러스터 멤버는 동적으로 바뀐다)를 찾는 초기 커넥션으로 사용하기 때문에, 모든 서버 리스트를 포함할 필요는 없다. (서버가 다운되었을 경우를 대비해 서버를 하나이상 적으면 된다)
key.serializer, value.serializer 기본 org.apache.kafka.common.serialization.ByteArraySerializer 전달받은 byte[]를 그대로 리턴한다.

buffer.memory  프로듀서가 서버로 보낼 레코드를 버퍼링 할 때 사용할 수 있는 전체 메모리의 바이트수. 레코드가 서버로 전달 될 수 있는 것 보다 더 빨리 보내지면 버퍼는 소진되고 프로듀서는 max.block.ms 동안 레코드를 보내지 않고 블럭 한다. 블럭을 피하려면 block.on.buffer.full(아래참고)을 false로 두면 된다.
 이 세팅은 대략 프로듀서가 사용할 메모리 이지만, 프로듀서가 사용하는 메모리가 버퍼링만 있는게 아니기 때문에 설정에 딱떨어 지지는 않는다. 처리중인 요청 때문에 유지 해야하는 메모리 뿐만 아니라 압축 설정이 켜있으면 압축하는데 부가적인 메모리가 사용된다.

기본값은 약 33MB
acks acks=0: acks를 0으로 설정하면, 서버에서 수신확인(acknowledment)이 오길 기다리지 않는다. 소켓 버퍼에 레코드가 즉시 추가되고 보내진것으로 간주된다. 이 경우에는 서버가 레코드를 수신했다는 보장이 없고, retries 설정도 먹지 않는다 (클라이언트는 통상 실패를 알지 못하기 때문에 retry를 할 수 없.. ). 각 레코드에 대해 되돌려 받은 오프셋은 항상 -1로 세팅 된다.acks=1: 리…

카프카 브로커 설정

카프카 브로커는 config/server.properties 파일에서 모든 설정을..

기본설정
broker.id 기본값은 0이다. 클러스터내에서 브로커를 구분 하는 이름으로 사용되며, 브로커를 구분하는 유니크한 값이기 때문에 브로커 호스트가 바뀌거나(다른 서버로 옮기거나) 포트가 바뀌어도 컨슈머(consumer) 설정을 바꾸지 않아도 된다.

host.name 기본값은 null이다. 값을 넣지 않으면 시스템에 있는 모든 인터페이스에 바인딩하고, 지정하면 특정 IP에 바인딩을 한다. 그래서 클라이언트가 특정 인터페이스에 접속하게 하려면 host.name을 지정하면 된다. 
port 카프카 브로커가 열고 있는 소켓 포트를 말한다.
log.dirs 카프카 브로커가 메세지를 파일로 저장 할 디렉토리를 말하는데,  콤마(,)로 구분해 여러 디렉토리를 지정 할 수 있다. 기본값은 /tmp/kafka-logs이다. 
기본 설정으로 브로커 하나를 띄워도 되고, 위 4가지만 설정만 조정하면 여러 브로커 인스턴스로 구성된 카프카 클러스터도 구성 할 수도 있다.  아래에서 살펴보자.
그 밖에,  advertised.host.name, advertised.port 가 있는데, advertised.host.name은 프로듀서, 컨슈머 그리고 다른 브로커들에 주어지는 호스트 이름으로 지정하지 않으면 host.name이 사용된다. advertised.port도 마찬가지로 프로듀서나 컨슈머 그리고 브로커에 접속 할 때 지정하는 포트로 지정되지 않으면 port 설정이 사용된다.

브로커가 시작될때 주키퍼에 IP/PORT가 등록 될때, InetAddress.getLocalHost.getHostAddress가 사용된다. 그래서 클라우드 환경이나 Docker, Vagrant 같은 환경일 경우는 가끔 consumer/producer가 브로커에 접속이 되지 않는 경우가 생긴다.  이때는 host.name을 속성을 지정하면 해결 할 수있다. 드물게 브로커에 바인딩된 IP/PORT와 클라이언트가 사용하는 …

자바에서 Zero Copy를 이용한 데이터 전송

리눅스나 유닉스에서 I/O 성능을 높이기 위해 sendfile() 시스템 호출을 이용해 "Zero Copy"기술을 사용한다. 자바에서는 어떻게 I/O 성능을 높이는가에 관한 글요약.

2008년에 쓰인 글이며 지금은 대중화 된 방법이다. 원문링크

웹 서버가 정적인 파일을 디스크에서 읽어서 소켓에 쓸때 커널 영역과 어플리케이션 영역간에 데이터 복사와 컨텍스트 전환으로 발생되는 비효율은 Zero Copy로 효율적인 처리를 할 수 있다.

Zero Copy는 디스크에서 소켓으로 데이터를 복사할 때 커널레벨에서 데이터를 복사하는 방식으로 CPU 사용율과 메모리 대역폭 사용도 줄이고 커널 모드와 사용자 모드간 컨텍스트 전환 비용도 줄일 수 있기 때문에 성능이 좋아진다.

자바는 java.nio.channels.FileChannel.transferTo() 메소드를 통해 Zero Copy를 제공 한다.
데이터를 전송하는 일반적인 방법
파일에서 데이터를 읽고 소켓에 쓰기까지는 사용자 모드와 커널 모드간 4번의 컨텍스트 전환이 일어난다. 그리고 데이터 복사도 4번 일어난다.







read() 호출은 사용자 모드에서 커널 모드로 컨텍스환트를 전환 하고, DMA( Direct Memorry Access) 엔진이 디스크에서 파일을 읽어 커널 영역 버퍼에 데이터를 저장한다. 이때  첫번째 복사가 생긴다.요청된 양만큼 읽기 버퍼에서 사용자 버퍼로 데이터가 복사되고, read() 호출은 읽은 데이터를 반환한다. 이때 또 한번 컨텍스트 전환이 생기며 데이터는 사용자 영역 버퍼에 저장된다. 두번째 복사.다시 send() 소켓 호출은 사용자 모드에서 커널 모드로 컨텍스트를 전환시키고, 커널 영역 버퍼로 데이터를 복사하는 세번째 복사가 생긴다.완료된 send() 시스템 호출은 값을 반환하고 네번째 컨텍스트 전환이 생긴다. 그리고 DMA 엔진이 커널 영역 버퍼에서 프로토콜 엔진으로 데이터를 복사한다. 네번째 복사.
사용자 버퍼에 바로 데이터를 쓰지 않고 "Intermediat…