카카오 코드 페스티벌 2018 예선 대회 개최 후기

요약

카카오 코드 페스티벌 2018 예선은 그냥 BOJ의 321번 대회일 뿐이지!

6,000여 명이 참가하는 대회를 매우 성공적으로 마친 BOJ의 입장에서 바라본 대회 후기

대회 문제는 여기를 클릭

카카오 코드 페스티벌 2018

카카오 코드 페스티벌은 카카오에서 주최하는 프로그래밍 대회입니다. 한국에서 열리는 많은 프로그래밍 대회가 그렇듯이 이 대회도 역시 참가 대상은 대학(원) 재/휴학생입니다.

대회는 총 예선과 본선으로 두 번 열리게 됩니다. 예선을 통과한 참가자 64명은 본선에 진출할 수 있게 되며, 본선의 상금과 인원은 매우 의미 있는 수입니다. 상금과 인원이 모두 2k의 형태를 가지고 있고, 각 상의 상금과 인원을 곱하면 모두 29가 됩니다. (카카오 보도자료대회 홈페이지)

이번에 열리는 카카오 코드 페스티벌은 2회 대회입니다. 2회 대회는 Baekjoon Online Judge의 대회 플랫폼을 이용해서 열리게 되었습니다.

UCPC 2018에서 이어지는 대회 플랫폼

BOJ는 이전에 LGE Code Jam을 위해 대회 플랫폼을 제공한 적이 있습니다. 단, 이 경우는 i18n의 문제 때문에, 뷰 만큼은 BOJ 소스를 일부 떼어내서 만들었습니다. (나머지는 부분은 공유합니다)

UCPC 2018 본선은 BOJ에서 사용하는 소스를 그대로 공유하면서 최소의 소스 코드 수정으로 만든 사이트입니다. 즉, BOJ 에서 보이는 UCPC 2018의 스코어보드UCPC 2018 에서 보이는 스코어보드가 모두 같은 위치에 있는 코드로 만들어진 페이지입니다.

BOJ는 이미 지난 300번의 내부/외부/공개/비공개 대회와 900만건의 채점으로 인해 안정성이 검증되었다고 볼 수 있습니다. (2018년 8월 8일 기준) 새로운 대회 사이트를 만들고, 채점 프로그램을 수정하는 것도 좋긴 합니다. 하지만, 신뢰성이 가장 중요한 대회 플랫폼에서 베타 서비스를 운영할 수는 없기 때문에, 매일 매일 테스트 중이나 다름없는 BOJ의 소스를 그대로 이용하는 것이 좋습니다.

카카오 코드 페스티벌 2018 예선도 역시 독립된 사이트로 대회를 열었습니다.

참가자의 수

카카오 코드 페스티벌 2018 예선을 위해 BOJ에서 준비할 내용은 많지 않았습니다. 어떻게 보면 이 대회는 그저 많은 참가자가 독립된 사이트에서 참가하는 321번 대회일 뿐이지요.

앞서 작성한 UCPC 2018 후기에도 적혀있지만, 온라인 대회에서 가장 중요한 점은 참가자의 수 입니다.

기록을 살펴보면 BOJ에서 연 대회 중에서 가장 많은 참가자가 참가한 대회는 Coder’s high 2016 Round 1: Online (2016년 5월 28일)이고, 참가자의 수는 648명입니다. 이 대회는 3인 1팀 대회였기 때문에, 최대 동시 접속자 648×3 = 1,944명 정도가 예상되었습니다. 이 당시의 기록을 보면 실제 동시 접속자는 최대 900명 정도 였고, 분당 페이지뷰는 최대 3100회 정도 였습니다.

2016년 당시에 저 동시 접속자 900명은 매우 기록적인 수치였지만, 2018년 현재는 그렇게 크게 의미있는 수치가 아니게 되었습니다. 분당 페이지뷰 3100회는 아직 조금은 의미 있는 수치이긴 하지만, BOJ에서 활동하는 유저들의 크롤러 덕분에 페이지뷰도 크게 의미있는 수치는 아닙니다.

카카오 보도자료에 의하면 1회 대회 참가자의 수는 4,000명 정도였다고 합니다. 이번 2회 대회를 열기 위해 BOJ에서 제공한 사용자 계정의 수는 6,600개였습니다.

BOJ에 아직 6,000여 명 이상이 동시 접속한 적은 없었기 때문에, 이 점에 있어서 조금 준비할 것들이 있었습니다.

채점 서버

놀랍게도 채점 서버는 전혀 문제가 되지 않습니다.

지금도 BOJ에서 빈번하게 벌어지는 재채점 때문에, 채점 서버를 매우 많이 켜고 있기 때문입니다.

지난 2018년 4월 1일은 매우 의미있는 재채점이 있었습니다. 바로, BOJ에서 가장 많은 사람이 제출한 알고리즘 문제인 1000번 – A+B, 1001번 A-B, 1008번 A/B, 2558번 A+B – 2를 재채점했기 때문입니다.

2018년 4월 1일 오후 5시부터 재채점을 시작했고, 이 재채점이 모두 완료된 시간인 4월 2일 오후 2시까지 재채점한 제출의 수는 총 294,767개입니다. 또, 재채점이 진행되는 동안 BOJ에 유저가 제출한 소스의 개수는 10,643개 입니다. 또, 재채점은 총 96대의 채점 서버를 이용해서 진행했습니다.

재채점에 걸리는 시간은 이론상으로는 모든 사람이 같은 시간에 제출을 했을 때 걸리는 시간과 같을 수 밖에 없습니다.

평균을 내보면 총 1시간에 14,543개의 제출을, 1분에 242개의 제출을 채점한 것과 같은 수치가 나옵니다.

대회는 총 6시간이었기 때문에, 대회 시간 동안 제출이 87,258개를 넘지 않는다면 충분히 채점은 밀리지 않는다는 것을 이 당시에 증명해냈습니다.

또, 대회 전용 아이디는 기존 BOJ 아이디에 비해 제출이 매우 적기 때문에, 채점 프로그램이 채점을 마무리 하는데 걸리는 시간이 1초를 넘지 않습니다.

실제로 채점 마무리 시간을 비교해보면 다음과 같습니다. (2018년 8월 8일 기준)

  • cubelover가 10947번 – 로또에 제출: 41.72초
  • baekjoon이 10947번 – 로또에 제출: 17.96초
  • python이 10947번 – 로또에 제출: 17.49초
  • cubelover가 1000번 – A+B에 제출: 28.83초
  • baekjoon이 1000번 – A+B에 제출: 22.10초
  • python이 1000번 – A+B에 제출: 18.80초
  • cubelover가 1427번 – 소트인사이드에 제출: 7.03초
  • baekjoon이 1427번 – 소트인사이드에 제출: 0.69초
  • python이 1427번 – 소트인사이드에 제출: 0.65초
  • cubelover가 1785번 – 보드 게임에 제출: 3.15초
  • baekjoon이 1785번 – 보드 게임에 제출: 0.41초
  • python이 1785번 – 보드 게임에 제출: 0.38초

참고할 통계

보통 대부분의 대회 문제는 12개를 넘지 않고, 예비 소집 문제도 4개를 넘지 않는게 일반적입니다. 따라서, 대회 유저는 최대 16개의 문제를 풀었다고 가정할 수 있습니다.

참가자는 6,000여 명 정도이기 때문에, 한 문제를 풀 수 있는 사람의 최대값은 6,000여 명입니다.

위에서 조사한 값에 의하면, 유저 python이 가장 대회 유저에 가까운 제출 수를 가지고 있고, 1427번 – 소트인사이드가 대회에서 가장 많이 풀린 문제와 가장 가까운 제출 수를 가지고 있다고 예상해볼 수 있습니다.

채점을 마무리하는데 걸리는 시간이 0.65초라는 것은 매우 짧은 시간입니다. 보통의 유저는 채점 현황에서 결과를 확인하고, 문제 페이지로 돌아가게 됩니다. 채점 마무리 시간은 채점 현황의 결과가 바뀐 다음부터 시작되는 시간입니다. 유저가 채점 현황에서 결과가 바뀐 것을 확인하고, 문제 페이지로 바로 이동했다고 해도 이 시간은 0.65초보다 짧은 것은 일반적으로는 불가능합니다.

결국 위의 내용을 종합해보면 대회 때 필요한 채점의 양은 BOJ 재채점에 필요한 채점의 양보다 작기 때문에, 충분히 별 문제가 안된다는 사실을 알 수 있습니다.

실제 대회가 진행된 동안 29,629개였습니다. 기록에 따르면, 각 유저가 제출한 시점부터 채점이 시작되기까지 걸린 평균 시간은 0.85초였습니다. 이 시간은 제출 버튼을 누르고 나서, 채점 현황으로 리다이렉트되는 시간보다 작기 때문에, 유저는 거의 기다리는 중을 못봤을 확률이 매우 높습니다.

웹 서버

웹 서버는 어차피 Auto Scale이 되기 때문에, 별로 걱정할 필요가 없습니다.

UCPC 2018 예선 때 경험했지만, 대회가 시작되는 시점에만 트래픽이 매우 몰립니다. 미리 서버를 여러 대를 켜서 대비했습니다.

Screenshot 2018-08-08 06.52.11

Screenshot 2018-08-08 06.54.05

위의 그림을 보면, 서버의 응답시간과 처리량을 볼 수 있습니다.

대회가 시작한 1시에 유저의 새로고침이 집중되었지만, 응답시간 450ms 이하로 대회 시작을 잘 견딘 모습을 볼 수 있습니다.

이후 2시 30분정도까지 처리량은 계속해서 늘었지만, 응답시간은 모두 50ms대로 잘 견뎌냈음을 볼 수 있습니다.

오후 2시 30분 이후에는 처리량은 점점 줄어드는데, 응답 시간은 점점 늘어나는 이상한 현상을 볼 수 있습니다.

이는 스팟보드가 너무 많은 제출을 changed_runs.json으로 받아오면, 실시간 스코어보드 업데이트가 잘 되지 않는 버그(스팟보드의 버그인지 BOJ의 버그인지 확인해봐야 함) 때문에, 스코어보드의 업데이트 방식을 runs.json으로 바꿨기 때문에, 스코어보드를 처음 그리는데 오래 걸렸기 때문입니다.

스팟보드가 100명 전후의 참가자가 참가할 때를 가정하고 만든 스코어보드라서 이런 현상이 벌어진 것으로 추측됩니다. 추후에 스팟보드의 소스를 보고 수정을 해야할 것 같습니다.

BOJ의 이 시기 평균 응답시간이 85.5ms였던 것을 보면, 두 사이트 모두 이 시기에 스코어보드를 제외하면 매우 빠르게 접속할 수 있었습니다.

DB 서버

DB 서버는 매우 중요합니다.

웹 서버의 스케일링은 매우 간단하지만, DB 서버는 다운타임이 발생할 수 밖에 없습니다.

따라서, 대회 당일 새벽에 DB 서버의 인스턴스 사양을 높이는 작업을 실행했었습니다.

덕분에 처음으로 BOJ의 임시 점검을 예고 하고 했었고, 임시 점검 페이지도 만들었습니다.

Screenshot 2018-08-04 01.54.38.png

인스턴스의 크기를 얼마나 높여야할지 매우 고민이 되었습니다.

대회 플랫폼 운영자의 입장에서 성공적인 프로그래밍 대회의 기준은 “대회가 진행되는 동안 잠을 잘 수 있는가” 입니다. DB서버가 다운되면, 대회가 진행되는 동안 잠은 잘 수 없습니다. 따라서, 일단 가능한 큰 크기의 인스턴스를 사용해보고, 여러가지 지표를 조합해서 다른 큰 규모에서 사용할 인스턴스의 크기를 결정하기로 했습니다.

결론은 선택한 인스턴스는 너무 큰 인스턴스였습니다. 모니터링 값으로만 보면 기존에 사용하던 DB를 그대로 사용했어도 전혀 문제가 없었을 수치였습니다.

하지만, 잠을 잘 수 있을 정도로 성공적인 프로그래밍 대회였기 때문에, 후회는 없는 인스턴스 크기였습니다.

이제 끝?

채점 서버도 모두 준비 되었고, 웹 서버도 모두 준비 되었습니다. 보험으로 DB 서버의 사양도 매우 크게 올렸기 때문에, 이제 모든 준비가 끝났다고 생각했습니다.

하지만 아니었습니다.

바로 채점 현황 실시간 업데이트에 사용하는 Pusher가 문제였습니다.

BOJ는 Pusher를 총 두 곳에 사용하고 있습니다.

  • 채점 현황: 실시간 업데이트를 위해
  • 대회 모든 페이지: 공지사항과 Q&A의 실시간 업데이트를 위해

예전에는 재채점할 때도 실시간 업데이트를 진행했지만, 재채점을 실시간으로 보는 사람의 수는 매우 적고, Pusher의 메시지 제한에 걸리기 때문에, 사용하지 않고 있습니다.

BOJ는 원래 Startup 플랜을 사용하고 있었습니다. 이 플랜에는 총 500개의 동시 연결, 1일 1백만 메시지 제한이 있습니다. 하지만, UCPC 2018 온라인 예선 때, 동시 연결 제한을 넘어버리는 바람에 급하게 Pro 플랜으로 업데이트해서 사용했습니다. Pro 플랜의 제한은 2,000개의 동시 연결, 1일 4백만 메시지입니다.

채점 현황은 유저가 가장 많이 보는 페이지 중 하나이지만, 가장 짧은 시간 보는 페이지입니다. 보통은 문제 페이지를 가장 많이 보고 있고, 채점 현황은 제출을 했을 때만 보는 페이지 입니다. BOJ에 존재하는 수많은 유저의 크롤러는 채점 현황 페이지를 가장 많이 방문하지만, 다행히도 크롤러는 자바스크립트를 끄고 활동하기 때문에, Pusher와는 무관합니다.

동시에 500명이 채점 현황을 보는 현상은 잘 벌어지지 않기 때문에, 평소에는 Startup 플랜으로도 충분합니다.

위에서도 언급했지만, 이 대회는 6,000여 명이 참가합니다. Pusher에서 가장 큰 Plan은 10,000개의 동시 연결까지 지원합니다. 대회 중에 Pusher 대시보드를 보면서 플랜을 올릴 준비를 해야 할 것 같았습니다.

그럼 이제, 메시지의 개수를 계산해보려고 합니다.

제출 1개의 업데이트는 최대 1(채점 준비중)+1(채점중)+100(채점 %)+1(최종 결과) = 103번 이루어지게 됩니다. 모든 문제의 데이터가 100개 이상이 아니기 때문에, 실제로는 103번보다 더 적은 횟수로 업데이트가 이루어집니다.

또한, 최초 1번은 Pusher가 아닌 Ajax를 이용해서 업데이트를 진행하고 있습니다. (이유는 다른 포스팅에 작성할 예정)

아무리 대회가 진행된다고 해도 제출이 100,000개는 넘지 않는다고 생각했기 때문에, 100,000 × 103 =  10,300,000 = 약1000만

Pusher에서 가장 큰 플랜은 1일 최대 2천만 메시지를 지원하기 때문에, 역시 플랜을 업그레이드하는 것으로 해결할 수 있습니다.

하지만, 대회를 위해 플랜을 올리는 것은 피하고 싶었기 때문에, 어떻게 하면 Pusher의 연결을 최소로 할지 고민을 하게 되었습니다.

채점 현황 실시간 업데이트

대회가 진행된다고 하더라도 BOJ의 문은 계속 열려있고, 대회가 열리지 않는 것 처럼 채점을 지원해야 합니다. BOJ를 사용하는 유저는 BOJ에서 다른 대회가 열린다는 사실을 홈페이지를 통해 눈치챌 수 없어야 성공적인 대회 플랫폼이라고 생각했습니다.

따라서, BOJ에서 실시간 업데이트를 빼는 것은 옵션에 없었습니다.

UCPC 2018 예선에서 가장 문제가 되었던 것은 동시 연결입니다. 동시 연결을 줄이는 몇 가지 방법을 생각했습니다.

첫 번째로 채점 현황이 비어있으면, Pusher를 연결하지 않았습니다.

이 날 가장 많은 트래픽이 몰릴 곳은 카카오 코드 페스티벌 홈페이지입니다. 이 곳은 대회 플랫폼이기 때문에, 채점 현황에 자신이 제출한 결과만 나옵니다.

BOJ는 채점 현황이 비어있는 일이 거의 없기 때문에, 항상 채점 현황에 접속하면 Pusher 연결을 시도하게 됩니다. 하지만, 대회가 시작하기 전 또는, 제출을 하기 전에는 채점 현황이 비어있기 때문에, 굳이 Pusher 연결을 만들 필요가 없습니다. 따라서, 채점 현황에 결과가 하나도 없으면 Pusher를 연결하지 않게 업데이트 했습니다.

두 번째로는 일정 시간이 지나면 Pusher의 연결을 끊어버렸습니다.

Pusher의 도움말 페이지에 따르면, 연결을 페이지당 1개로 센다고 합니다. 즉, 한 유저가 채점 현황을 총 다섯 개의 탭에 열면, 연결은 5개가 늘어나는 방식입니다.

대회 때는 시간이 매우 촉박하기 때문에, 탭을 닫지 않고 문제를 풀 확률이 매우 높습니다.

탭 1개에서 문제 1개를 열고, 제출하고, 결과를 확인하고, 다음 문제를 열고, 제출하고, …. 이렇게 반복한다면 동시 연결은 정말 큰 문제가 되지 않겠지만, 시간이 급한데 탭을 끄지 않을 확률이 매우 높습니다.

공지사항으로 “Pusher의 동시 연결이 부담되니 채점 현황 결과를 확인하면 꼭! 탭을 꺼주세요” 라는 메시지를 보내는 것은 정말 너무 최악입니다. 이건 절대로 하지 않을 행동이기도 합니다.

어차피 채점 결과는 금방 금방 나옵니다. 데이터의 용량이 매우 크고, 개수가 매우 많은 문제가 아니면 보통 오래 기다려봐야 1분이면 채점 결과가 나옵니다.

따라서, 채점 현황이 로딩된지 5분이 지나면, 자동으로 Pusher와의 연결을 끊고 위에 메시지를 표시하기로 했습니다.

Screenshot 2018-08-08 07.34.21.png

결국 이 두 가지를 조합해서 대회가 진행된 동안 평소보다 오히려 더 낮은 Puhser 동시 접속을 기록하는데 성공했습니다.

위에서 계산한 바에 의하면 이 대회 때, 기다리는 중 -> 채점 준비중으로 바뀌는데 걸린 시간은 약 0.85초였습니다. 각 제출을 채점하는데 걸린 평균 시간은 3.51초 입니다. 또, 따라서, 5분은 적당한 시간이었습니다.

Google Analytics에 의하면 채점 현황 페이지는 총 14.43%의 페이지 뷰를 기록했습니다. 또, 평균 페이지에 머문 시간은 32초였습니다. 어쩌면, 위의 업데이트를 하지 않아도 충분히 Pusher는 견뎌냈을 것 입니다.

지금은 Pusher 접속 유지 시간을 6시간으로 늘려놓은 상황입니다.

대회 페이지 실시간 업데이트

사실 UCPC 2018 예선 때 동시 접속이 카카오 코드 페스티벌 2018 예선보다 많았던 이유는 채점 현황이 아닙니다. 위에서도 통계를 언급했지만, 채점 현황은 겨우 14%의 페이지 뷰를 기록했고, 유저가 평균 32초 머무르기만 했습니다.

바로 UCPC 2018 예선 때 Pusher의 리밋을 넘어섰던 이유는 대회의 모든 페이지에 Pusher가 깔려있기 때문이었습니다.

실제로 이 사실을 위의 채점 현황 업데이트를 모두 하고 나서 깨달았습니다.

채점 현황이야 30초 정도의 짧은 시간만 방문하면 되고, 금방 채점 결과가 뜹니다. 따라서, 화면의 상단에 메시지를 표시하면 새로고침 한 번 하는거야 별로 어려운 일이 아닙니다.

하지만, 6시간이나 진행되는 대회에서 5분마다 저 메시지가 뜬다면, 정말 짜증나지 않을까요?

결국 Pusher의 플랜을 올린다는 플랜 B를 계획하고, Pusher의 대체 서비스를 찾기 시작했습니다.

약 30분간의 조사 끝에 Ably를 현재 대회 공지사항/Q&A  실시간 업데이트에 사용하기로 결정했습니다.

Ably의 플랜은 Pusher와 다르게 사용한 만큼만 내는 방식이었습니다. Price Calculator에서 6,000개의 동시 접속과 20만개의 메시지 (설정할 수 있는 최소값)을 계산해보니 $102 달러가 나왔습니다. 이 정도의 가격이면 Pusher의 플랜보다 훨씬 저렴하기 때문에, 1일용으로 사용하기로 결정했습니다.

Ably의 적용은 어렵지 않았습니다. Pusher 메시지를 보내는 부분을 단순히 Ably로 바꾸면 되는 것 이었습니다. JS는 Pusher 라이브러리 대신 Ably 라이브러리를 사용하고, 함수명 몇 개만 바꾸면 되는 수준이었습니다. 약 5분 정도 걸린 것 같습니다.

테스트를 해보니 매우 만족스럽게 동작했습니다.

Ably의 플랜에 적혀있는 Burstable to 2.5x of prepaid quota를 보고 3,000 동시 접속으로 플랜을 결정했습니다.

대회가 끝나고 보니 동시 접속의 최대값은 648이었습니다. 이정도면 그냥 Pusher를 사용해도 충분히 현재 플랜에서 견딜 수 있는 수치이긴 했습니다.

하지만, 성공적인 대회는 대회 플랫폼 운영자가 잠을 잘 수 있어야 하기 때문에, 잘한 선택이었습니다.

시간이 남아서 채점 업데이트도 Pusher 대신 Ably를 사용하게 수정해봤지만, 원하는 결과가 나오지 않아 그냥 계속해서 Pusher를 사용하기로 결정했습니다.

Pusher는 보낸 순서대로 유저의 웹 브라우저에 도착했는데, Ably는 순서가 조금 섞이는 문제가 있었습니다.

모든 준비가 끝났고, 대회는 매우 성공적으로 마쳤습니다.

대회 플랫폼 운영자, 대회 운영자, 대회 문제 출제자 모두 성공적인 프로그래밍 대회의 기준에 속하는 대회였던 것 같습니다.

대회가 진행되는 동안 발견한 몇 가지 불편한 점은 모두 BOJ에 업데이트로 적용될 예정입니다.

거의 대부분 대회 운영자에게 필요한 기능입니다. 대표적으로 Q&A 페이지의 페이지네이션과 답변 없는 질문 부터 보기, 기본 답변 프리셋 설정하기 등이 있습니다.

가장 아쉬운 점은 스팟보드였습니다. 스팟보드가 6,000여 명의 참가자를 감당하기엔 아직 힘들어보였습니다.

이후 벌어진 일

대회가 종료된 후에 DB 서버의 인스턴스를 다시 정상으로 내리는 작업이 필요했습니다. 이 작업을 수행하려면 다시 서버 점검 페이지를 열어야 합니다.

어차피 DB 서버 인스턴스를 바꾸려면 다운 타임이 발생하니, 이 시기에 MySQL의 버전을 올리기로 결정했습니다. 그런데, 이상하게 버전을 올리니 CPU Utilization이 평소의 2배가 되었고, 100%를 찍는 경우도 매우 많이 발생했습니다. 결국 채점 마무리 시간이 30분이 걸리는 현상까지 말생했습니다. 그래서, 게시판에는 이런 글까지 올라왔지요.

버전을 다시 내리는 것은 불가능하기 때문에, 일단 이틀 동안은 원인을 파악하는 시간을 가졌습니다. 일단 채점은 계속 해야 하니 평소보다 더 많은 대수의 채점 서버를 켜고, 로또와 같이 봇들이 주로 제출하는 문제를 10분에 한 번 제출할 수 있게 임시 조치 했습니다.

버전을 올린 후에 테이블이 최적화되지 않아 발생하는 문제라고 파악되었습니다. 새벽에 서버를 내리고, 모든 테이블을 최적화 (optimize table) 시켰습니다. 최적화 이후에 오히려 버전업을 하기 전보다 CPU Utilization 낮아졌고, 채점 마무리 시간이 평균 1~2초 (cubelover의 로또 제출 기준) 빨라지는 의도치않은 효과까지 얻게 되었습니다.

Ably는 결국 1일용으로 끝났습니다. 그쪽에서도 뭔가 이상했는지, 기껏 돈 냈는데 하루만에 갑자기 downgrade한게 정상인지 물어보는 메일이 왔습니다.

Pusher는 현재 플랜을 유지하기로 결정했습니다. 이제 동시 연결이 아닌, 메시지 개수가 이전 플랜의 제한을 넘어가버렸습니다.

카카오 코드 페스티벌 2018 예선 대회 개최 후기”에 대한 답글 4개

댓글 남기기

About Baekjoon

스타트링크 블로그에서 지루한 글을 담당하고 있습니다!