tcp 파일을 이용해서 현재 접속 현황을 가지고 오는 자바로 만들어진 프로그램이 있다.
이 프로그램에서 cpu 사용량이 15% 이상을 치는 문제가 발생했다.
리눅스에서 tcp와 udp의 소켓 정보는 /proc/net/tcp, tcp5, udp, udp6 파일에서 확인 할 수 있다.
문제의 프로그램은 위 파일을 읽고 파싱하여 데이터를 가져온다.
커넥션이 적을 때는 문제가 없지만, 커넥션이 많아지면서 문제가 발생한 것이다.
커넥션 수가 20000개가 넘어가면 읽는 시간은 느려지지 않지만, cpu사용율이 15% 가까이 발생한다.
커넥션 수가 50000개가 넘어가면 전체 데이터를 읽어오는 시간은 20초 가까이 걸리며 cpu사용율을 100% 가까이 사용한다.
tcp, udp 파일에서 하나의 라인은 하나의 커넥션이다.
처음에는 5만 라인이 굉장히 많은 줄 알았다. 그러나 /proc/net/tcp 파일을 복사해서 그 복사한 파일을 읽었더니 굉장히 빨랐다.
/proc/net/tcp 파일 자체가 문제였던 거다. 구글링으로 문제에 대해 검색을 시작했다.
구글링 후 알게 된 하나는 netstat명령과 ss 명령의 차이점이었다. 둘 다 네트워크의 상태를 보는 명령이지만 구조 자체가 다르다.
netstat은 /proc/net/tcp 파일을 읽어들인다. 그렇기 때문에 커넥션이 많을 때는 netstat 명령 역시 느려진다.
반대로 ss 명령은 커넥션이 많을 때도 굉장히 빠르다.
ss 커맨드는 AF_NETLINK 를 이용하여 커널과 직접 통신하기 때문이다.
AF_NETLINK를 이용하기 위해서는 C 언어를 이용해야 했다. C 언어 자체는 잘 모르지만 예제 샘플을 이용해서 원하는 형태의 프로그램은 만들 수 있을 것 같았다.
만들어진 프로그램을 JNI을 이용해서 가지고 오면 될것으로 봤다.
여기에는 몇가지 문제가 있었다. kernel 과 직접 통신하기 때문에 커널 버전에 맞는 각각의 실행파일을 따로 준비해야 한다. (문제가 있었던 프로그램은 여러 서버에서 돌아가야 했다.)
커스터마이징을 한다고 해도 c 코드 자체를 수정하기가 쉽지 않다. 관리포인트가 늘어나는 문제도 있다.
고민을 거듭하다 방향을 바꿔서 그냥 ss 명령을 사용하는 방법을 생각했다.
ss 명령은 iproute 패키지의 일부분이다. iproute 패키지는 소스가 공개되어있다.
문제가 되었던 프로그램이 돌아가던 운영체제는 대부분이 centos나 redhat이었다.
centos 4,5,6,7 버전의 minimal 설치 패키지를 조사하여 iproute 패키지가 있는 지 확인하였다. 전부 있는 것으로 확인하였다.
ss 커맨드를 이용한 방법으로 개발을 진행하겠다고 컨펌을 받고 개발을 진행하였고 잘 마무리 되었다.
나중에 알게된 솔라윈즈에서 작성한 글이 딱 내가 겪었던 일을 잘 설명해 주어서 링크한다.
댓글 없음:
댓글 쓰기