반응형

이전 블로그에서 2017년 8월 7일에 작성한 글


 

대부분의 웹 서버 (Web Server)는 디폴트로 GET, POST, HEAD 이외의 요청 메소드는 막아둔다.

Restful API를 제공하는 웹 어플리케이션이 웹 서버로부터 위 세가지 이외의 요청 메소드를 받으려면 WebtoB (버전 4.1) 에서는 다음과 같이 설정해야 한다.

 

$WEBTOB_HOME/config/ws_engine.m 파일에 다음을 추가한다.

*NODE

WEBTOBDIR = ...

SHMKEY = ...

...

METHOD = "GET, POST, HEAD, DELETE, PUT"

 

설정을 변경하였으므로 wscfl ​명령어로 설정을 적용하고 WebtoB를 재부팅 한다.

 

반응형
반응형

Kafka는 Consumer가 자신이 읽은 위치의 offset을 기록하도록 commit을 하도록 한다.

이때 자동 커밋과 수동 커밋으로 나뉜다.

 

자동 커밋

자동 커밋은 특정 주기마다 커밋을 자동으로 하는 방식이다. 하지만 자동 커밋은 컨슈머 그룹의 리벨런싱이 발생할 때 중복 또는 유실이 발생한다.

 

1. 메시지 유실

자동 커밋의 주기가 1초라고 가정하였을 때, 메시지를 poll 하고 처리하던 컨슈머가 메시지를 처리하는데 오래 걸려 1초를 초과한 후에 장애가 발생할 경우, 이미 커밋을 하였기 때문에 해당 메시지는 더 이상 처리할 수 없다. 따라서 메시지 유실이 발생한다.

 

2. 메시지 중복

자동 커밋의 주기가 5초라고 가정하였을 때, 메시지를 poll 하고 컨슈머가 5초 이내에 메시지를 처리하였다. 하지만 어떠한 이유로 해당 컨슈머가 죽게 되면, 해당 메시지의 대한 커밋은 처리하지 못한 상태가 된다. 따라서 다른 컨슈머가 메시지를 중복하여 처리한다.

 

수동 커밋

수동 커밋은 Consumer 코드에서 명시적으로 커밋하는 방식이다. 수동 커밋은 커밋 위치에 따라 메시지 중복 또는 유실이 발생한다.

 

1. 메시지 유실

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);
consumer.commitAsync();
... // 메시지 처리 코드

위와 같이 메시지를 poll을 하고, 바로 커밋을 하게 되면 offset은 기록되어 이 메시지는 더 이상 중복되어 처리되지 않는다. 하지만 메시지를 처리하는 코드에서 에러가 발생할 경우, 해당 메시지와 함께 가져온 메시지들은 처리하지 못하고 유실이 발생한다.

 

2. 메시지 중복

ConsumerRecords<String, String> records = consumer.poll(Long.MAX_VALUE);
... // 메시지 처리 코드
consumer.commitAsync();

위 코드는 메시지 유실을 방지하기 위해 컨슈머가 메시지를 poll을 하고, 바로 커밋을 하는 것이 아니라 메시지를 처리하는 코드를 선행한 후에 커밋을 하였다. 하지만 메시지 처리하는 코드에서 에러가 발생할 경우 커밋을 하지 못한다. 이 경우 다시 메시지를 가져오기 때문에 이미 처리한 메시지들은 중복이 발생하게 된다. 이와 같이 메시지가 중복은 발생할 수 있어도 최소 한 번은 전달되는 방식을 at least once(최소 한 번)이라고 한다.

 

메시지 중복 방지

메시지 유실은 수동 커밋을 사용한다면 방지가 가능하다. 하지만 수동 커밋을 사용한다고 하더라도 메시지 중복이 발생한다. 메시지 중복을 막을 수 있는 방법은 무엇일까?

 

kafka에서는 exactly-once를 지원한다. 하지만 이 기능은 producer-kafka(broker)-consumer의 파이프라인 동안에 오직 한 번만 전달되는 의미이다. 즉 producer 쪽에 발생할 수 있는 메시지 유실에 더 집중한 기능이다. 이 기능을 사용한다고 해도 수동 커밋에 의한 메시지 중복을 피할 수 있는 것은 아니다. 따라서 컨슈머의 중복처리는 따로 로직을 작성해야한다.

 

 

1. 메시지를 DB에 insert만 하는 경우

컨슈머의 역할이 로깅과 같은 메시지를 DB에 저장하는 작업이라면 중복은 큰 문제가 되지 않는다. PK와 같은 식별자를 통해 DB 자체에서 검증할 수 있으므로 해당 예외만 처리하여 구현하면 된다.

try {
	dao.insert(log);
} catch (DataIntegrityViolationException ex) {
	logger.error("Log insert error. {}", log, ex);
}

 

2. 메시지를 DB에 insert 후에 다음 메시지는 update 하는 경우

상태와 같은 로그성 메시지일 경우, 처음 들어온 메시지는 insert를 해야 할 것이고 이후에 들어온 동일한 식별자는 update를 해야 하는 경우 아래와 같이 코드를 작성할 수 있다.

try {
	dao.insert(log);
} catch (DataIntegrityViolationException ex) {
	logger.error("Log insert error. {}", log, ex);
	dao.update(log);
}

 

하지만 위 코드는 파티션이 2개 이상이고, 라운드 로빈 방식으로 파티션에 나눠 보내면 문제가 발생한다. 최종 상태가 먼저 insert 된 후, 초기 상태가 이후에 처리되어 update 될 수 있기 때문이다. 또한 메시지 유실이 발생할 경우 각각의 처리하는 컨슈머가 다르므로 뒤죽박죽 처리될 것이다.

 

따라서 상태를 반영해야 하는 메시지일 경우 카프카는 파티션에 대해서는 메시지 순서를 보장하므로 동일한 식별자인 메시지에 대해서는 동일한 파티션으로만 보내야 한다. 이렇게 하면 메시지 유실이 발생한다고 하여도 메시지의 순서는 보장되므로 최종 상태도 정상 반영된다.

 

다만 위와 같이 코드를 작성할 경우 DB에 항상 먼저 insert를 한 후에 문제가 발생하면 update를 처리하므로 DB에 부하가 심하다. 따라서 상태와 같은 항목을 조건으로 하여 아래와 같이 작성하는 게 성능상으로 좋다.

	public void process() {
		if(TransactionProcessStatusEnum.PROGRESS == status) {
			insert(log);
		} else {
			int result = dao.update(log);
			if (result <= 0) {
				insert(log);
			}
		}
	}
	
	public void insert(Log log) {
		try {
			dao.insert(log);
		} catch (DataIntegrityViolationException ex) {
			logger.error("Log insert error. {}", log, ex);
			dao.update(log);
		}
	}

 

3. 온라인(즉시적인) 메시지 처리일 경우

 

반응형
반응형

이슈

카프카가 Failed to clean up log for __consumer_offsets 에러를 발생시키고, 몇 분 뒤에 Shutdown broker because all log dirs in 에러를 남기고 비정상 종료되는 현상이다.

 

공식 이슈

https://issues.apache.org/jira/browse/KAFKA-6188

 

[KAFKA-6188] Broker fails with FATAL Shutdown - log dirs have failed - ASF JIRA

Just started with version 1.0.0 after a 4-5 months of using 0.10.2.1. The test environment is very simple, with only one producer and one consumer. Initially, everything started fine, stand alone tests worked as expected. However, running my code, Kafka cl

issues.apache.org

https://github.com/apache/kafka/pull/6403

 

KAFKA-6188; Fix windows clean log fail caused shut down by theidexisted · Pull Request #6403 · apache/kafka

During debugging, I find that delete or rename a file before close it is illegal on windows, so I changed the function deleteSegment to add a direct close handle operation. I have manually test it ...

github.com

 

공식 이슈로 올라온 것은 2017년 11월 버전 1.0.1이고, 2018년 8월 버전 2.0부터는 패치되었다고 한다.

하지만 21년 6월 버전 2.6까지도 계속 발생하는 것으로 봐서는 아직까지 해결되지 않은 것으로 판단된다.

 

 

원인

카프카는 data를 retention 주기만큼 보관하고 있다가 이후 삭제한다. 이때 Cleaner가 동작하게 되는데, 삭제해야 하는 데이터의 로그 파일이 존재하지 않을 경우 위와 같은 에러가 발생한다.

 

처음 이슈가 발생했을 때 Windows에서만 발생하는 이슈라고 하였지만, 현재는 여러 OS에서 발생하고 있다.

 

어떤 개발자가 말하기로는, 카프카의 데이터 로깅 위치(log.dirs)를 변경할 경우 발생한다고 한다. 하지만 디폴트 설정으로 사용한 개발자도 해당 이슈가 발생한다고 한다.

 

아직 까지 정확한 원인과 이슈 해결이 되지 않았다.

 

 

 

해결

많은 사람들이 가장 많이 해결한 방법으로는 kafka의 data 경로에 모든 파일을 삭제하면 된다.

server.properties 파일에 아래 설정 경로에 있는 데이터를 모두 삭제하면 된다. (카프카 토픽에 저장했던 데이터들이 모두 삭제된다.)

log.dirs=/home/kafka/kafka/logs

 

하지만 이렇게 해도 되지 않을 경우, 다음으로는 주키퍼의 data 파일을 삭제한다.

zookeeper.properties 파일에 아래 설정 경로에 있는 데이터를 모두 삭제하면 된다. (카프카 토픽 자체가 모두 삭제된다.)

dataDir=/home/kafka/kafka/zookeeper

 

이렇게 해도 되지 않을 경우, 재설치를 추천한다.

반응형

'서버 > Kafka' 카테고리의 다른 글

[KAFKA] Consumer 메시지 중복 처리  (0) 2021.12.06
반응형

Grafana는 시계열 데이터에 대한 대시보드를 제공해주는 Data Visualization Tool이다.

 

Grafana 설치

wget https://dl.grafana.com/oss/release/grafana-7.3.7-1.x86_64.rpm
sudo yum install grafana-7.3.7-1.x86_64.rpm

 

 

Grafana 실행

  • 버전 및 운영제에 따라 실행방법은 https://grafana.com/docs/grafana/latest/installation/ 참고
  • Red Hat, CentOS, RHEL, and Fedora(64 Bit), v7.3.7으로 설명
  • OS버전에 따라 systemctl 명령어가 다를 수 있음.
    • ex) CentOS 6 ⇒ sudo service grafana-server start
# 데몬 리로드
sudo systemctl daemon-reload

# 실행
sudo systemctl start grafana-server

# 확인
sudo systemctl status grafana-server

 

Grafana 로그인

Grafana Data Source 설정

  • 정보를 수집할 Data Source를 설정한다.
  • 대시보드 첫 화면에서 ‘Add your first data source’를 클릭 또는 왼쪽에 톱니바퀴(Configuration)을 누르면 나타나는 ‘Data sources’를 클릭하여 등록할 수 있다.
반응형

'서버' 카테고리의 다른 글

프록시 서버 (포워드 프록시, 리버스 프록시)  (0) 2021.08.20
반응형

프록시 서버란

프록시란 클라이언트와 서버 중간에 위치하여 중개 역할을 하는 서버이다. 위키피디아에서는 아래와 같이 설명한다.

 

프록시 서버(영어: proxy server 프록시 서버[*])는 클라이언트가 자신을 통해서 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해 주는 컴퓨터 시스템이나 응용 프로그램을 가리킨다. 서버와 클라이언트 사이에 중계기로서 대리로 통신을 수행하는 것을 가리켜 '프록시', 그 중계 기능을 하는 것을 프록시 서버라고 부른다.
- wikipedia

 

프록시를 사용하는 목적은 다양하다.

일반적으로 사내망에서 외부망과 통신을 한 곳에서 관리하기 위하여 포워드 프록시를 사용하는 경우가 있으며, 클라이언트의 요청을 한곳에서 받아 로드밸런싱 하기 위하여 리버스 프록시를 사용하는 경우가 있다.

 

포워드, 리버스 프록시

프록시는 포워드 프록시와 리버스 프록시로 구분하여 사용한다.

 

포워드 프록시

  • 클라이언트가 서버에 직접 요청을 하는 것이 아닌, 프록시 서버가 해당 요청을 받아 클라이언트가 요청한 서버에 프록시가 대신 요청하여 응답을 받아 전달해주는 형태
  • 클라이언트는 자신이 요청할 서버를 알고 있음
  • 일반적으로 사내망과 외부망을 분리하기 위해 사용

포워드 프록시

리버스 프록시

  • 클라이언트가 프록시에 요청을 하면, 프록시가 해당 요청을 적절한 서버에 요청하여 응답을 받아 전달해주는 형태
  • 클라이언트는 프록시 서버만 알고 있음. 즉, 해당 요청을 처리할 서버를 알지 못함
  • 일반적으로 로드밸런싱을 위해 사용

포워드 프록시

 

포워드 프록시 경우의 수

포워드 프록시는 요청의 프로토콜, 프록시 서버의 프로토콜에 따라 경우의 수는 다음과 같다.

 

1. HTTP to HTTP

HTTP to HTTP

 

2. HTTP to HTTPS

HTTP to HTTPS

 

3. HTTPS to HTTP

HTTPS to HTTP

4. HTTPS to HTTPS

HTTPS to HTTPS

반응형

'서버' 카테고리의 다른 글

Grafana 설치 및 실행  (0) 2021.09.16

+ Recent posts