이번에는 라인 유튜브에 올라와있는 것을 보고 정리한 글입니다.

 

틀린 내용이 있을 수도 있습니다. 틀린 내용이 있다면, 알려주시면 감사하겠습니다.

 

 

 

문제 상황

 

kafka broker를 rolling restart 했을 때,

message produce가 실패하는 현상 발생 했음.

-> produce reqeust timeout이 발생했다고 함.

 

restart 했던 broker의 response time은 정상이였지만, producer의 request latency가 거의 16초나 되었다고 함.

 

 

왜 이런 현상이 나타났을까?

그렇다면 request는 어떠한 과정으로 일어나는 지?

 

producer -> broker -> producer 이런 식으로 latency를 측정함.

broker는 데이터를 완전히 받는 직후부터 시간을 측정함.

 

 

broker를 restart 했을 때, node_netstat_TcpExt_SyncookiesSent가 spike였음(값이 높았음)

 

TCP SYN Cookies에 대해 알아야함.

이는 syn flloding을 막기 위해 이용하는 것임.

 

SYN flood attack 이란?

 

TCP 통신할 때, syn 만 보내고, SYN + ACK 을 무시함. 그러면 서버는 syn queue에 이 SYN을 보관하다가 다 차게 됨.

그러면 syn cookie를 이용하게 됨. 

 

syn cookie는 SYN 패킷에 있는 정보들을 이는 SYN + ACK의 ISN(Initial Sequence Number)로 만들어서 클라이언트에게 보냄.(원래는 random 값) 클라이언트가 서버에게 ACK을 보내면, 이 ACK의 정보를 decoding해서 connection을 맺게 됨.

 

 

 

 

그럼 왜 SYN flood가 일어났는지?

 

broker를 restart하면, 이 broker에 접속했던 client들이 일단 다른 broker에 접근을 하게 됨. restar가 되면, client는 broker들에게 fail-over를 하게 됨. 그리고 본래 broker들에게 기존 client들이 접속하게 됨.

연결하려는 client가 많아져서 syn flood 가 일어남.

 

 

tcp window가 문제가 됨?

요약하면, tcp window는 receiver가 처리할 수 있는 만큼의 양만 달라고 하는 것.

만약 데이터가 들어오는 속도가 처리 속도보다 빠르다면 데이터가 유실될 수 있음.

 

tcp 옵션에 window scaling 라는 옵션이 있음. 이는 windowsize * (2^scaling) 값이 최종 window size가 됨.

이를 이용하는 이유는 기존 window size의 최대값이 16비트 밖에 되지 않아서 그럼.

하지만 SYN cookie의   seq number는 32bit임. window scaling factor를 이용하지 못하게 됨.

-> 이는 한 번에 보낼 수 있는 데이터의 양이 적어지고 이는 throughput을 감소시킴.

 

근데 linux는 tcp timestamp가 유효하면, 이를 이용해서 window scaling 을 내장하는 기능이 있음.

그리고 scaling factor가 없어진다고 해도, timeout이 일어나는지?

 

 

실제로 net.ipv4.tcp_syncookies 값을 2로 설정하고 테스트해봤다고 함.

-> 모든 connection을 syncookies를 이용하여 연결함.

 

window scaling이 유효해야 하는 상태에서 지연이 일어나고 있었음?(잘 모르겠음)

-> broker 의 response time은 정상이지만, producer는 그렇지 않았음.

 

producer는 ack을 계속 기다리고 있었음. window size(789)가 작아서 이러한 현상이 일어났다고 함

 

window scaling 값도 1이였음. 즉 실제 window size는 789 * 2 ^ 1 = 1578이였음. 

 

 

그럼 왜 이렇게 window size가 작았을까?

커널을 분석해봤다고 함. 근데 서로 window size가 달랐음.

출처 : https://www.youtube.com/watch?v=_2F_qdwfUas&ab_channel=LINEDevelopers

broker의 window scaling factor가 7로 나옴(아까는 1로 나왔었음)

즉, producer는 1로 인지하고 있고, broker는 7로 알고 있음.(64배 차이남)

그래서 계속 기다리고 있었음.

 

실제 적용되는 값을 찾기 위해,

리눅스 커널의 tcp_select_window 함수로 window scaling 값을 조절함. 그래서 이를 hook 하는 방법을 생각함?

BPF를 이용하면 이 부분이 가능하다고 함. 유저가 작성한 프로그램이 커널에서 작동할 수 있다고 함.

 

실제 broker의 window scaling 값은 7이였음. 7을 이용하여 window size를 계산했음.

 

broker는 window scaling foactor를 7로 알고 있는 상태에서 데이터를 보냄., producer는 1로 알고 있는 상태임.

producer는 window size가 작았음. producer는 데이터를 보낼 때 마다 ack을 기다리고 있었음. 그렇기 때문에 producer reqeust 시간이 오래 걸리게 되고, 이는 timeout을 발생시킴.

 

왜 브로커 > producer 의 값과 실제 connection에 이용되는 값이 달랐을까?

-> 커널의 소스 코드에 문제가 있었다고 함.(linux kernel 3.10) 5.10 버전에 이 버그 해결되었다고 함.

 

 

해결책

 

이를 해결하기 위해, syn flood가 일어나지 않았다고 판단하도록 하게 했음.

즉, syn cookie를 끄는 방법.

-> 이는 syn flood가 일어나는 동안 syn 을 drop 하게 됨. 정상적인 접속이기 때문에 syn retry를 하게 됨. 이는 지연이 발생할 수 있음.

 

kafka의 listen backlog size를 늘리면 된다고 함. 하지만 이는 50으로 하드코딩 되어 있어서 늘릴 수 없다고 함.

이 부분을 논의 중임.

 

 

느낀 점

정말 대단하다고 느꼈습니다. 백엔드 개발자의 cs 지식이 정말 중요하다는 것을 느끼게 되었습니다.

 

궁금한 점이 하나 있습니다.

처음에는 단순히 window size가 작아서 발생한 문제라고 처음에는 이해했었습니다.

근데 broker window scaling factor가 1이면, window size의 문제는 아닌 것 같네요.

 

그렇다면 syn flood가 일어났고, 이 때문에 syn cookie를 이용해서 통신을 하게 되는데 커널 버그 때문에 서로 window size가 다르게 알고 있어서 이런 이슈가 발생한 것으로 이해했습니다.

 

그렇다면, 이 버그가 해결된 5.10 버전의 커널을 사용할 때는 syn cookie(syn flood가 일어나도)를 이용해도 이러한 문제점이 발생하지 않는 걸까요?

 

 

 

window size가 다르게 되면 어떠한 현상이 일어나는 지 알아볼 필요성이 있는 것 같습니다.

 

 

출처 : https://www.youtube.com/watch?v=_2F_qdwfUas&ab_channel=LINEDevelopers 

https://en.wikipedia.org/wiki/SYN_cookies

반응형

'BackEnd > Kafka' 카테고리의 다른 글

[Kafka] partition, consumer, producer 관계 (2)  (0) 2023.02.08
[Kafka] partition, consumer, producer 관계 (1)  (0) 2023.02.08

+ Recent posts