※ 동일한 오퍼레이션을 두 개 이상 선언하면 doOn* 은 선언 순서대로, doAfter* 은 선언 역순으로 실행된다.

 

doOnComplete

마지막 요소가 방출될 때, onCompelete 바로 전에 실행됨. onComplete와 마찬가지로, 에러가 발생하면 실행되지 않음.

 

doOnDispose

구독을 해지했을 때 실행됨.

 

doOnNext

요소를 방출할 때, onNext 바로 전에 실행됨.

 

doOnError

오퍼레이션 중 에러가 발생했을 경우, onError 바로 전에 실행됨.

 

doOnEach

doOnComplete, doOnNext, doOnError의 통합 버전. Notification<?>을 아규먼트로 받아 isOnComplete, isOnNext, isOnError로 각각에 맞는 처리를 할 수 있음.

 

doOnSubscribe

구독 시, onSubscribe 바로 전에 실행됨.

 

doOnLifecyle

doOnSubscribe, doOnDispose의 통합 버전.

 

doOnTerminate

Observable이 종료될 때, onComplete 또는 onError 바로 전에 실행됨. doOnComplete 또는 doOnError가 선언되어 있다면 선언한 순서대로 실행됨. (업스트림 -> 다운스트림)

 

doAfterNext

요소를 방출할 때, onNext 바로 후에 실행됨.

 

doAfterTerminate

Observable이 종료될 때, onComplete 또는 onError 후에 실행됨. (cancel, dispose시에는 실행되지 않음) doFinnally가 선언되어 있다면 그 후에 실행됨.

 

doFinally

Observable이 종료될 때 실행됨. doAfterTerminate가 Observable의 완료 또는 에러에 대해서만 실행되지만, doFinally는 cancel, dispose시에도 실행된다. doAfterTerminate가 선언되어 있다면 doFinally가 먼저 실행된다.

 

 

실행 순서

doOnSubscribe -> doOnNext -> onNext -> doAfterNext -> 선언 순서에 따라 doOnComplete / doOnError 또는 doOnTermitate -> doFinally -> doAfterTerminate

subscribeOn, observeOn 이 두 가지의 차이에 대해 비교해 놓은 글이 상당히 많다. 

 

그냥 아래 다섯 가지만 기억하자.

 

1. observeOn 은 다운스트림에만 영향을 준다.

2. subscribeOn 은 업스트립, 다운스트림 양쪽에 영향을 준다.

3. 한 Observable에 대한 두 번 이상의 subscribeOn 호출은 첫 번째 호출만 유효하다.

4. 한 Observable에 대한 observeOn 호출은 몇 번이고 유효하다.

5. observeOn으로 변경된 쓰레드는 subscribeOn으로 변경할 수 없다.

 

출처:

https://proandroiddev.com/rx-java-subscribeon-and-observeon-a7d95041ce96

 

RxJava subscribeOn and ObserveOn

SubscribeOn and ObserveOn, two concepts that eludes most Rx beginners . I too belonged to this before my experiments using them. Below is a…

proandroiddev.com

 

 

JUnit 5 는 JDK 8+ 을 요구한다. 

 

때문에 org.junit.jupiter.api.Assertions.. 를 사용하면 오류가 발생한다. (내부에서 Function 시리즈를 사용함.)

JUnit api 는 JUnit 4 이하의 org.junit.Assert... 를 사용해야 한다.

 

그리고 JUnit 5 에서, 이전 버전과의 런타임 호환성을 위한 vintage 를 의존성에 추가한다:

	testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.0'
	testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.0'
	testImplementation "junit:junit:4.12"
	testRuntimeOnly 'org.junit.vintage:junit-vintage-engine:5.5.0'
	testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.0'

5.6.0 이상을 사용하니 아래와 같은 오류가 발생했다. 고쳐서 사용할 수 있는 방법이 있을 수 있으나, 일단 5.5.0 을 사용하기로 한다.

 

* What went wrong: 
Execution failed for task ':compileTestJava'. 
> Could not resolve all files for configuration ':testCompileClasspath'. 
   > Could not resolve org.junit.jupiter:junit-jupiter-api:5.6.0. 
     Required by: 
         project : 
      > Cannot choose between the following variants of org.junit.jupiter:junit-jupiter-api:5.6.0: 
          - javadocElements 
          - sourcesElements 
        All of them match the consumer attributes: 
          - Variant 'javadocElements' capability org.junit.jupiter:junit-jupiter-api:5.6.0: 
              - Unmatched attributes: 
                  - Found org.gradle.category 'documentation' but wasn't required. 

iif(condition: () => boolean, trueResult: SubscribebaleOrPromise = EMPTY, falseResult: SubscribableOrPromise = EMPTY): Observable

 

첫 번째 인자로 주어진 predicate fucntion을 실행하여, true일 경우 두 번째 인자가 반환하는 Subscribable 또는 Promise를, false일 경우 세 번째 인자가 반환하는 Subscribable 또는 Promise를 구독한다.

 

iff 사용 시 주의할 점이 있다.

 

아래 코드를 실행한다고 하면,

...
const source = of('Some value');
const whenTrue => (v) => {console.log('Do you expect it to be executed only if true?') return of('true!')};
const whenFalse => (v) => {console.log('Do you expect it to be executed only if false?') return of('false!')};

source.pipe(
	mergeMap(v => 
    	iif(_ => v === 'Some value',
			whenTrue(v),
			whenFalse(v)
        ))
).subscribe(console.log);

 

source의 값은 'Some value' 이기에, 콘솔에는 다음과 같이 찍힐 거라고 생각할 수 있다:

Do you expect it to be executed only if true?
true!

 

실행 결과는 다음과 같다:

Do you expect it to be executed only if true?
Do you expect it to be executed only if false?
true!

 

 

whenTrue, whenFalse는 iff의 실행 시점에 인자 evaluation시에 실행되고, predicate function의 결과가 true이니 'true!'를 출력했다.

 

아주 당연한 결과이지만, iif 를 분기 동작에 사용하려고 할 때 쉽게 실수할 수 있는 부분인 것 같아 굳이 정리해둔다.

 

Thymeleaf 를 사용하면 meta, link 태그 등의 닫기 태그가 없어 SAX 파싱 예외가 발생하는 경우가 있다. 일반적인 html에서는 저런 태그를 닫아주지 않아도 이런 경우가 없는데, 정확히 어느 버전까지인지는 모르겠지만, 예전 버전의 Thymeleaf lib 사용 시 xhtml의 엄격한 룰이 적용되어 이와 같은 현상이 발생한다고 한다.

 

이를 피하기 위해서는,

1. application.properties 에 다음 프로퍼티를 설정한다:

spring.thymeleaf.mode=LEGACYHTML5

 

2. nekohtml 의존성을 추가한다:

net.sourceforge.nekohtml:nekohtml

 

ps: nekohtml은 버전 1.9.15 이상을 사용하라는 권고가 있음.

 

select

- 전통적인 방식으로, 대부분의 os가 지원.

- 프로세스가 커널에 파일 디스크립터(이하 FD) 상태를 직접 조회.

- 한 번에 다수의 FD를 조회하여 I/O 상태를 관찰.

- 때문에 무한 루프 방식으로 지속된 polling 필요 (CPU 낭비).

- 한 번에 조회할 수 있는 FD의 수는 1024로 제한됨.

- timeout 사용 방식에 따라 blocking이 될 수도, non-blocking이 될 수도 있음.

 

 

poll

- 기본적인 작동 방식은 select와 유사함.

- 조회 FD의 개수 제한이 없음.

- select에 비해 os specific하여, 이식성이 상대적으로 나쁨.

 

 

epoll

- 개선된 poll으로, 이벤트 기반으로 작동.

- 관리 FD 개수 무제한.

- 커널이 FD의 상태를 직접 관리하며, 상태가 변경된 FD를 던져줌.

- 때문에 커널로의 통신에 따른 오버헤드가 대폭 줄어듦.

 

 

IOCP (Input/Output Completion Port / Overlapped IO)

- 입출력을 담당할 포트를 지정하여 처리.

- 내부에 큐를 두어, 입출력이 완료되었음을 큐에 저장.

- non-blocking. 백그라운드로 작동.

- async 방식으로, 콜백 사용 가능.

 

 

IO

- NIO가 나오면서 자바의 기존 IO 방식은 OIO(Old I/O)라고도 불림.

- *InputStream, *OutputStream, *Reader, *Writer...

- 전통적인 blocking call 방식.

- 때문에 FD(소켓, 파일...) 당 하나의 쓰레드가 필요함.

- 때문에, 동시 요청이 자주 발생하는 어플리케이션의 경우 필연적으로 쓰레드 풀을 사용하게 됨.

 

 

NIO

- New I/O 로, 자바 1.4에서 등장.

- 주요 요소: Buffer, Charset, Channel, Selector.

- Buffer: NIO의 데이터 저장 컨테이너로, 다이렉트 버퍼, 논 다이렉트 버퍼(힙 버퍼)로 나뉨. 다이렉트 버퍼는 네이티브 메모리를 사용하고, 논 다이렉트 버퍼는 JVM의 힙 메모리를 사용함.

- Channel: 데이터가 오고 가는 양방향 통로.

- Selector: non-blocking, 이벤트 방식으로, 지정한 채널에 발생한 이벤트를 수신하여 이벤트 유형에 맞는 동작을 처리할 수 있음. 

- 결정적으로, OIO에서는 다수의 요청을 받아들이기 위해 많은 수의 쓰레드를 필요로 했지만, NIO에서는 Selector를 조회하는 하나의 쓰레드만으로 다수의 요청을 커버할 수 있음. 물론 요청의 성격에 따라 별도의 처리 쓰레드가 필요할 수 는 있다.

- 자바 6 부터는 epoll을 지원하여, 런타임 os가 리눅스 커널 2.6 이상이라면 epoll을 디폴트로 한다. poll을 사용하려면 아래와 같이 시스템 프로퍼티로 제어 가능함.

System.setProperty("java.nio.channels.spi.SelectorProvider", "sun.nio.ch.PollSelectorProvider");

- 이렇게, NIO는 os specific하다. os의 기능을 차용하여, 아래와 같이 런타임 os에 따라 동작을 달리한다.

Windows: select

Mac OS: Kqueue

리눅스 커널 2.6+: epoll

솔라리스: poll

 

 

NIO2

- 그냥 NIO로 통틀어 말하기도 함. 자바 1.7에서 등장. 네트워킹 I/O에는 마이너한, 파일 I/O에는 메이저한 변화가 있었음.

- Async* 시리즈의 등장으로, 비동기 콜백 방식의 I/O를 지원함.

'Java > Core' 카테고리의 다른 글

Java 13 간략히 정리  (0) 2020.07.16
Java 12 간략히 정리  (0) 2020.07.15
Java 11 간략히 정리  (0) 2020.07.15
Java 10 간략히 정리  (0) 2020.07.15
람다  (0) 2020.01.05

7.6.0 릴리즈 버전 기준으로 작성됨

==

 

Filebeat는 lumberjack 프로토콜(over TCP)을 통해 Logstash(이하 로그스태시)로 다이렉트로 이벤트 전송이 가능하다.

 

로그스태시를 아웃풋으로 두려면 엘라스틱서치 아웃풋은 사용하지 않아야 한다. 그리고 아래와 같이 로그스태시 url을 설정한다.

output.logstash:
  hosts: ["127.0.0.1:5044"]

이 설정을 위해서는 반드시 엘라스틱서치 인덱스 템플릿을 로드해야 한다. 인덱스 템플릿을 자동으로 불러오는 옵션은 엘라스틱서치 아웃풋일 때만 작동한다.

 

 

옵션

아래 옵션들은 filebeat.yml 의 logstash 섹션에 지정한다.

 

 

enabled (디폴트: true)

이 아웃풋을 활성화하는지 지정한다. 아웃풋을 사용하지 않으려면 false로 세팅한다.

 

 

hosts

Filebeat가 연결할 로그스태시 서버 주소를 설정한다. 로드밸런싱 적용 시 둘 이상의 호스트를 설정한다. 디폴트 포트는 5044가 된다.

 

 

compression_level (디폴트: 3, 사용안함: 0)

gzip 압축 레벨을 설정한다. 압축을 사용하지 않으려면 0 을 세팅한다. 세팅 범위는 1~9이다. 값이 낮을수록 압축률은 떨어지고 속도는 올라간다. 높을수록 네트워크 사용량을 줄어들지만 cpu 사용률이 올라간다.

 

 

escape_html (디폴트: false)

HTML 문자열 이스케이핑 설정. true로 세팅하면 이스케이핑을 활성화한다.

 

 

worker

logstash로 이벤트를 전송하는 워커의 수를 설정한다. 설정되는 수는 host 당 워커의 수이다. 2개의 호스트를 설정하고 worker 값이 3이라면 총 워커의 수는 6이 된다.

 

 

loadbalance (디폴트: false)

다수의 호스트를 설정하고 이 옵션을 true로 세팅하면 로드밸런싱을 활성화한다. 어떤 호스트로 이벤트를 전송할지는 랜덤으로 결정되며, 우선순위는 없다. 다수의 호스트를 설정하더라도 이 옵션값이 false이면 로드밸런싱은 적용되지 않고, 설정된 호스트 중 오직 한 호스트로만 모든 이벤트를 전송한다 (이 때의 대상 호스트도 랜덤으로 결정). 그리고 그 호스트의 응답이 없을 경우 다른 호스트로 전송을 시도한다.

예:

output.logstash:
  hosts: ["localhost:5044", "localhost:5045"]
  loalbalance: true
  index: filebeat

호스트로의 로드밸런싱은 커넥션 레벨에서 이루어진다. 이벤트 레벨이 아니다. 이벤트는 한 번 맺어진 커넥션으로만 고정적으로 전송되며, 로드밸런싱은 로그스태시로의 기존 커넥션이 끊어지고 커넥션을 다시 맺을 때 어떤 호스트로 커넥션을 맺을지 결정하는 과정에 적용된다.

 

 

ttl (디폴트: 0 (사용안함))

로그스태시 호스트로의 커넥션 유지 시간을 설정한다. 로드밸런싱을 적용할 때 유용하다. 로그스태시로의 커넥션은 sticky하기 때문에, 로드밸런싱의 목적인 커넥션의 분산이 고르지 못하게 이루어질 수 있다. 이 옵션을 설정함으로써 일정 시간 후 커넥션을 끊었다가 다시 맺도록 하여, 커넥션이 고루 분산되도록 할 수 있다.

 

이 옵션은 async 로그스태시 클라이언트에는 아직 지원되지 않는다 ("pipelining" 옵션).

 

 

pipelining (디폴트: 2, 사용안함: 0)

로그스태시로부터의 ACK를 기다리는 동안 비동기로 전송할 이벤트 묶음(batch)의 수를 설정한다. 아웃풋은 많은 수의 pipelining 묶음이 한 번 작성될 때 블로킹된다.

 

 

proxy_url

로그스태시로 연결 시 SOCKS5 프록시를 사용할 URL을 설정한다. 설정 URL은 반드시 socks5:// 스킴을 포함해야 한다. 로그스태시로의 연결은 HTTP 기반이 아니기 때문에, web-proxy는 사용할 수 없다.

 

SOCKS5 프록시가 클라리언트 인증을 요구하는 경우, username, password는 아래와 같이 URL에 포함시킬 수 있다.

프로시를 사용할 때는 호스트 이름은 클라이언트가 아닌, 프록시 서버로 리졸빙되어야 한다. 이 설정은 proxy_use_local_resolver 옵션으로 설정한다.

 

예:

output.logstash:
  hosts: ["remost-host:5044"]
  proxy_url: socks5://user:password@socks5-proxy:2233

 

 

proxy_usr_local_resolver (디폴트: false)

프록시를 사용할 때, 로그스태시 호스트 이름이 로컬에서 리졸빙되도록 설정한다. 디폴트는 false로, 즉 프록시를 사용하면서 호스트 이름의 리솔루션은 프록시 서버에서 수행한다는 의미이다.

 

 

index

이벤트에 작성할 인덱스 루트 이름을 설정한다. 디폴트는 Beat 이름이 된다.

 

 

ssl

로그스태시 연결을 위한 SSL 파라미터 옵션을 설정한다 (예: root CA). SSL을 사용하려면 반드시 로그스태시의 비트 인풋 플러그인 설정을 통해 SSL/TLS를 사용해야 한다.

 

 

timeout (디폴트: 30 (초))

로그스태시 서버와의 타임아웃을 시간을 초 단위로 설정한다. 여기에 설정된 시간동안 로그스태시 호스트로부터 응답이 없으면 타임아웃.

 

 

bulk_max_size (디폴트: 2048, 사용안함: value <= 0 )

로그스태시로의 한 번의 요청에 담길 수 있는 이벤트의 최대 개수를 설정한다. Beat가 보내는 하나 하나의 이벤트들은 모아져서 묶음이 되는데, Beat가 bulk_max_size의 값을 넘어서는 이벤트 묶음을 발행하면 이 묶음을 쪼갠다.

 

이벤트 묶음을 더 크게 설정하면, 이벤트 전송 횟수가 줄어들고, 결국 이벤트 전송 시 발생하는 오버헤드가 줄어들어 성능을 향상시킬 수 있다. 하지만 동시에, 큰 이벤트 묶음은 처리 시간을 늘어나게 할 수 있는데, 이는 API 에러, 커넥션의 끊어짐, 요청 타임아웃 등의 원인이 되어 결과적으로 처리량에 악영향을 미치게 된다.

 

bulk_max_size에 0 보다 작거나 같은 값을 설정하여 이 기능을 비활성화하면, 한 이벤트 묶음에 포함될 이벤트의 수는 큐가 결정하게 된다.

 

 

slow_start (디폴트: false)

true로 설정 시, 트랜잭션 당 한 이벤트 묶음의 부분 집합만을 전송한다. 에러가 없다면 전송되는 이벤트의 수는 최대 bulk_max_size까지 증가한다. 에러 발생 시 전송되는 이벤트의 수는 다시 줄어든다.

 

 

backoff.init (디폴트: 1s)

네트워크 에러 발생 후 로그스태시로의 재연결을 시도하기까지 대기하는 시간을 초 단위로 설정한다. 재연결 시도가 실패하면 대기 시간은 재연결 시도 횟수에 비례하여 증가하는데, 최대 backoff.max까지 증가한다. 연결에 성공하면 타이머는 리셋된다.

 

 

backoff.max (디폴트: 60s)

네트워크 에러 발생 후 로그스태시로의 재연결을 시도하기까지 대기하는 시간의 최대치를 설정한다.

 

7.6.0 릴리즈 버전 기준으로 작성됨

==

 

인풋, 모듈 설정을 외부 파일에서 불러올 수 있다.

 

인풋 설정

예:

filebeat.config.inputs:
    enabled: true
    path: inputs.d/*.yml

path 에서 잡히는 각 파일은 반드시 하나 이상의 input 설정을 가지고 있어야 하며, 각 파일의 첫 라인은 반드시 인풋 선언으로 시작해야 한다 (- type).

 

예:

- type: log
  paths: 
    - /var/log/mysql.log
  scan_frequency: 10s
  
- type: log
  paths: 
    - /var/log/apache.log
  scan_frequency: 5s

 

 

서로 다른 두 인풋이 같은 파일 경로를 대상으로 삼지 않돌고 해야한다. 둘 이상의 하베스터가 같은 파일을 동시에 읽게 되면 예상할 수 없는 상황이 발생할 수 있다.

 

 

모듈 설정

설정 방법은 인풋과 유사하지만, 모듈 설정을 불러오는 디폴트 경로는 modules.d 디렉토리라는 점이 다르다.

 

예:

filebeat.config.modules:
    enabled: true
    path: ${path.config}/modules.d/*.yml

modules 커맨드로 모듈 설정을 활성화/비활성화하려면 path는 반드시 modules.d 디렉토리로 설정해야한다.

 

path 에서 잡히는 각 파일은 반드시 하나 이상의 module 설정을 가지고 있어야 하며, 각 파일의 첫 라인은 반드시 모듈 선언으로 시작해야 한다 (- module).

 

예:

- module: apache
  access: 
    enabled: true
    var.paths: [/var/log/apache2/access.log*]
  error:
    enabled: true
    var.paths: [/var/log/apache2/error.log*]

 

'ELK+Filebeat' 카테고리의 다른 글

Filebeat 공통 옵션  (0) 2020.02.15
Filebeat Log input 설정  (0) 2020.02.13
Filebeat 동작 방식  (0) 2020.02.13
ELK-Filebeat 연동 기본 설정  (0) 2020.02.12

7.6.0 릴리즈 버전 기준으로 작성됨.

==

 

여기의 옵션들은 모든 인풋에 사용할 수 있다. 한 곳에 설정하면 모든 인풋에 적용된다는 뜻이 아니다(general configuration). 인풋 타입이 관계 없이 사용할 수 있다는 뜻이다.

 

enabled (디폴트: true)

이 인풋의 활성화/비활성화를 설정한다.

 

 

tags

Filebeat가 발행하는 각 이벤트의 tags 필드에 포함될 태그를 설정한다. 태그는 키바나에서 특정 이벤트를 선택하는 일이나 Logstash에서의 조건부 필터링 적용에 유용하게 사용된다. 여기에 설정한 태그는 일반 설정(general configuration) 태그에 추가된다.

예: tags ["json", "note"]

 

 

fields

커스텀 필드 설정. 아웃풋에 포함될 추가적인 정보를 설정한다. 예로, 로그 데이터 필터링에 사용하기 위한 필드를 추가할 수 있다. 필드는 스칼라 값, 배열, 딕셔너리 혹은 이들이 중첩된 다른 어떠한 것이든 가능하다. 기본적으로 여기에 지정하는 필드는 아웃풋 도규먼트의 fields 서브딕셔너리로 그룹핑된다. fields_under_root 옵션을 true로 설정하여 커스텀 필드를 탑 레벨 필드로 둘 수 있다. 일반 설정(general configuration)의 필드와 중복 시 여기의 필드가 우선한다.

 

 

fields_under_root (디폴트: false)

true로 지정 시 아웃풋의 커스텀 필드를 탑 레벨 필드로 설정한다. false이면 fields의 서브딕셔너리로 그룹핑된다. 

 

 

processors

인풋 데이터에 적용되는 프로세서 목록이다.

 

 

pipeline

인풋이 생성하는 이벤트의 Ingest node 파이프라인 ID를 설정한다. 엘라스틱서치 아웃풋의 ID와 겹친다면 여기의 것이 우선한다.

 

 

keep_null (디폴트: false)

true로 지정 시 null 값을 지닌 필드도 아웃풋에 포함된다.

 

 

index

포맷팅된 문자열을 통해 인풋이 생성하는 이벤트의 인덱스를 설정하는데, 엘라스틱서치 아웃풋에 대해서는 index를 덮어쓰고, 다른 아웃풋에 대해서는 메타데이터의 raw_index 필드를 세팅한다. 설정 문자열에 사용할 수 있는 동적 필드는 에이전트 이름, 버전, 이벤트 타임스탬프가 있다. 다른 동적 필드를 사용하고 싶다면 output.elasticsearch.index 혹은 processor를 사용해야 한다.

예: "%{[agent.name]}-myindx-%{+yyyy.MM.dd}"

- 결과: "filebeat-myindex-2019.11.01"

 

'ELK+Filebeat' 카테고리의 다른 글

Filebeat 설정 파일 분리하기 (inputs, modules)  (0) 2020.02.15
Filebeat Log input 설정  (0) 2020.02.13
Filebeat 동작 방식  (0) 2020.02.13
ELK-Filebeat 연동 기본 설정  (0) 2020.02.12

+ Recent posts